美文网首页
自定义View-RootView和DecorView

自定义View-RootView和DecorView

作者: 韩明泽 | 来源:发表于2019-02-13 19:12 被阅读23次

    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

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