自定义View-RootView和DecorView

ViewRoot指的是ViewRootImpi,它是连接WindowManager和DecorView的桥梁,view的三大流程(测量、布局、绘制)都需要ViewRoot来完成。

  • 它是view的根,他控制View的测量、布局、绘制
  • 它持有WindowSession通过Binder与WMS通信。

目录

  • ViewRoot在哪里被创建又如何关联DecorView和WindowManager的
  • ViewRoot是如何完成view的三大流程
  • DecorView的基础概念

1. ViewRoot在哪里被创建又如何关联DecorView和WindowManager的

ViewRootImpl是在WindowManagerGlobal的addView()发方法中被创建的。当Activity在ActivityThread中被创建后紧接着会将DecorView添加到Window中,同时也会创建ViewRootImpl,并将ViewRootImpi和DecorView关联起来。
下面为WindowManagerGlobal中addView()的部分源码:

public void addView(View view, ViewGroup.LayoutParams params,
                    Display display, Window parentWindow){
    ...
    synchronized (mLock) {
        ...
        //创建ViewRootImp
        root = new ViewRootImpl(view.getContext(), display);
        ...
    }
    try {
         //关联WindowManager和DocorView
        root.setView(view, wparams, panelParentView);
    } catch (RuntimeException e) {
        ...
        throw e;
    }
}

下面为ViewRoot的setView()的部分源码

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
         ...
        mView = view;
            ...
        requestLayout();
            ...
        try {
                ...
            res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                    getHostVisibility(), mDisplay.getDisplayId(),
                    mAttachInfo.mContentInsets, mInputChannel);
        } catch (RemoteException e) {
               ...
        }
    }
}

在setView中传入的view就是DecorView他被赋值给mView这个会在performTraversals()中赋值给host用于参与顶层view的测量和绘制。setView()方法还会先调用requestLayout(),完成布局的第一次layout过程,然后调用addToDisplay(),来添加Window(mWindowSession.addToDisplay调用的是Session的addToDisplay()方法)。

  @Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
                        int viewVisibility, int displayId, Rect outContentInsets,
                        InputChannel outInputChannel) {
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
            outContentInsets, outInputChannel);
}

2. ViewRoot是如何完成view的三大流程

performTraversals()方法调用是通过scheduleTraversals()中handler去异步调用mTraversalRunnable接口该,最后该接口中的run()方法又调用了doTraversal()方法才调起了performTraverse()。

void doTraversal() {
    if (mTraversalScheduled) {
       ...
        try {
            performTraversals();
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        ...
    }
}

ViewRoot的performTraversals()是该类的核心,因为真正开始绘制是从调用这个方法开始。

performTraversals()部分源码:

private void performTraversals() {
    //将DecorView赋值给host,用于view的测量、布局和绘制
    final View host = mView;
    if (!mStopped) {
          ...
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
          ...
    }
          ...
    if (didLayout) {
        performLayout(lp, desiredWindowWidth, desiredWindowHeight);
         ...
    }
    if (!cancelDraw && !newSurface) {
         ...
        performDraw();
    }
    ...
}

3. DecorView的基础概念

DecorView是界面的顶级View,一般它是由一个竖向的LinearLayout和状态栏组合成(一些特殊机型还会有导航栏),LinearLayout布局中有标题栏和内容栏(content)组合而成(可参考下图)。

  • 内容栏是一个FrameLayout布局
  • Activity的setConentView()方法就是在内容栏中增加View
  • findViewById(android.R.id.content)获取的是内容栏
  • contentView.getChildAt(0)获取的是当前Activity布局文件的跟布局,也就是我们在layout文件设置的顶层的view。

下图为DecorView的层级关系图:


image

参考

Android窗口机制(四)ViewRootImpl与View和WindowManager

你可能感兴趣的:(自定义View-RootView和DecorView)