美文网首页
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