2023-10-07 基于加載顯示流程對Window的定位理解

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

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,都會創(chuàng)建一個ViewRootImpl,并將它保存在WindowManagerGlobal的ArrayList<ViewRootImpl> mRoots中,而這個根view也會保存在它的變量ArrayList<View> mViews中; 根view所有的參數(shù)保存在ArrayList<WindowManager.LayoutParams> mParams中。

普通View添加到VG是就是把該View加入到VG的mChildren數(shù)組中而已。

#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的實現(xiàn)類,其實是個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用于保存窗口狀態(tài),并且win.openInputChannel(outInputChannel);開啟事件傳輸通道。將IWindow和windowstate保存到一個map中,window持有session,wms從而將應用層各個IWindow和seession以及windowstate一一對應起來。這會用于判斷事件分發(fā)到哪個窗口和具體分發(fā)中用到。

上面是resume中的過程,調用addView()顯示過程,在resume之前,setcontentview并沒有顯示,只是創(chuàng)建了decorview,windowmanagerservice還不知道有新的window,當handleResumeActivity()中調用addView()之后才會ipc通知windowmanagerservice添加新的window并顯示。

windowManagerImpl 為 wWindowManager 的實現(xiàn)類。WindowmanagerImpl 內部方法實現(xiàn)都是由代理類WindowManagerGlobal完成,而WindowManagerGlobal 是一個單例,也就是一個進程中只有一個windowManagerGlobal 對象服務于所有頁面的View。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。