美文网首页
2023-10-07 基于加载显示流程对Window的定位理解

2023-10-07 基于加载显示流程对Window的定位理解

作者: 无极小屋 | 来源:发表于2023-11-14 18:19 被阅读0次

    整体流程非常多,本文看其中一部分。

    Window从逻辑理解来看,犹如是View的一个容器,Activity上所有显示的View都会包括在这一个Window之中。但是它并不是一个真正的View,从功能上来讲,Window更像是View的帮助类和整体管理类,不管是setContentView或者findview还有getxxtitle、settheme等等,都是通过Window来做的。

    //ActivityThread#handleResumeActivity
    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) { 
        //...
        ActivityClientRecord r = performResumeActivity(token, clearHide); // 这里会调用到onResume()方法
    
        if (r != null) {
            final Activity a = r.activity;
    
            //...
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow(); // 获得window对象
                View decor = r.window.getDecorView(); // 获得DecorView对象
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager(); // 获得windowManager对象
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l); // 调用addView方法
                }
                //...
            }
        }
    }
    

    WindowManager的addView()是针对根View(即 DecorView)的添加接口,子view的addview()不会掉用到它,每一个addview都是根view,都会创建一个ViewRootImpl,并将它保存在WindowManagerGlobal的ArrayList<ViewRootImpl> mRoots中,而这个根view也会保存在它的变量ArrayList<View> mViews中; 根view所有的参数保存在ArrayList<WindowManager.LayoutParams> mParams中。

    普通View添加到VG是就是把该View加入到VG的mChildren数组中而已。

    #ViewGroup.java
    
          private void addInArray(View child, int index) {
            View[] children = mChildren;
            final int count = mChildrenCount;
            final int size = children.length;
            if (index == count) {
                if (size == count) {
                    mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
                    System.arraycopy(children, 0, mChildren, 0, size);
                    children = mChildren;
                }
                children[mChildrenCount++] = child;
            } else if (index < count) {
                if (size == count) {
                    mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
                    System.arraycopy(children, 0, mChildren, 0, index);
                    System.arraycopy(children, index, mChildren, index + 1, count - index);
                    children = mChildren;
                } else {
                    System.arraycopy(children, index, children, index + 1, count - index);
                }
                children[index] = child;
                mChildrenCount++;
                if (mLastTouchDownIndex >= index) {
                    mLastTouchDownIndex++;
                }
            } else {
                throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
            }
        }
    
    //之后设置child.mParent = this;
    

    WindowManager的addView()则是针对DecorView

    #WindowManagerGlobal.java
    
    mViews.add(view);
    mRoots.add(root);
    mParams.add(wparams);
    ...
    root.setView(view, wparams, panelParentView, userId);
    
    #ViewRootImpl.java #setView(...)
    ...
    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                                getHostVisibility(), mDisplay.getDisplayId(), userId,
                                mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
                                mTempControls, attachedFrame, compatScale);
    
    //其中还包括inputChannel!!!
    ...
    

    上面的mWindow并不是刚开始那个Window,而是在ViewRootImpl中新建的一个IWindow的实现类,其实是个Binder对象,

    #ViewRootImpl.java
    
    mWindow = new W(this);
    
    
    static class W extends IWindow.Stub {
            private final WeakReference<ViewRootImpl> mViewAncestor;
            private final IWindowSession mWindowSession;
    
            W(ViewRootImpl viewAncestor) {
                mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
                mWindowSession = viewAncestor.mWindowSession;
            }
    ...
    }
    

    也就是说把当前Binder传到了WindowManagerService中去,WindowManagerService通过这个W和应用进程通信,类似于ActivityManagerService和ApplicationThread的通信。W中也维护了一个主线程Handler

    WindowManagerService会生成windowstate用于保存窗口状态,并且win.openInputChannel(outInputChannel);开启事件传输通道。将IWindow和windowstate保存到一个map中,window持有session,wms从而将应用层各个IWindow和seession以及windowstate一一对应起来。这会用于判断事件分发到哪个窗口和具体分发中用到。

    上面是resume中的过程,调用addView()显示过程,在resume之前,setcontentview并没有显示,只是创建了decorview,windowmanagerservice还不知道有新的window,当handleResumeActivity()中调用addView()之后才会ipc通知windowmanagerservice添加新的window并显示。

    windowManagerImpl 为 wWindowManager 的实现类。WindowmanagerImpl 内部方法实现都是由代理类WindowManagerGlobal完成,而WindowManagerGlobal 是一个单例,也就是一个进程中只有一个windowManagerGlobal 对象服务于所有页面的View。

    相关文章

      网友评论

          本文标题:2023-10-07 基于加载显示流程对Window的定位理解

          本文链接:https://www.haomeiwen.com/subject/jbjpbdtx.html