ViewRootImpl介绍

1. 简介

从上一篇文章:从setContentView揭开DecorView 中可以看到,Activity是怎么将我们的布局加载到DecorView,但是这时还不是可见的,因为这时布局还没有绘制。那么它是怎么绘制的,我们来研究一下。

本文源码基于android 27

2. 源码分析

虽然DecorView已经被创建出来了,但是目前DecorViewPhoneWindow是没有任何关系的。那么DecorView是怎么添加到PhoneWindow上面的呢。这个操作实际上在Activity启动时就完成了,关于Activity的启动可以看下这篇文章:Activity启动过程详解。我们直接来看相关代码,在ActivityThreadhandleResumeActivity()会将DecorView添加到PhoneWindow上面:

2.1 ActivityThread的handleResumeActivity

   final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
            
            //...
            
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();//获得当前Activity的PhoneWindow对象
                View decor = r.window.getDecorView();//获得当前phoneWindow内部类DecorView对象
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();//得当当前Activity的WindowManagerImpl对象
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl != null) {
                        impl.notifyChildRebuilt();
                    }
                }
                if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
                        wm.addView(decor, l);//将DecorView添加到当前Activity的窗口上面
                    }
                    
            //...
        }

WindowManager是个抽象类,其具体实现为WindowManagerImpl,我们直接看WindowManagerImpl中的addView()方法:

2.2 WindowManagerImpl的addView

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);//调用WindowManagerGlobal的addView方法
    }

这里的mGlobalWindowManagerGlobal类型,我们继续往下看

2.3 WindowManagerGlobal的addView

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        
        //...
        
        ViewRootImpl root;
        View panelParentView = null;

        //...

        root = new ViewRootImpl(view.getContext(), display);//创建一个ViewRootImpl对象

        //...
        
        root.setView(view, wparams, panelParentView);//将DecorView到ViewRootImpl中
        
        //...
    }

我们再来看看ViewRootImplsetView()

2.4 ViewRootImpl的setView

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                
                //...
                
                requestLayout();//请求布局
                
                //...
                
    }

继续往下看:

2.5 ViewRootImpl的requestLayout

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();//①
        }
    }
    
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);//②
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();//③
        }
    }
    
    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            performTraversals();//④

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

通过一系列的调用,最终会走到performTraversals()这个方法:

2.6 ViewRootImpl的performTraversals

    private void performTraversals() {
    
        //...
        
        //获得view宽高的测量规格,mWidth和mHeight表示窗口的宽高,lp.widthhe和lp.height表示DecorView根布局宽和高
        int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
        int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);//执行测量
        
        //...
        
        performLayout(lp, mWidth, mHeight);//执行布局
        
        //...
        
        performDraw();//执行绘制
        
        //...
    }

performTraversals()会执行View绘制的三大流程:测量,布局,绘制。好了,先到此为止吧。

2.7 时序图

最后,上张时序图:

ViewRootImpl相关时序图.png

3. 总结

measurelayoutdraw这三大流程先不分析,下文再来分析。
从上面的分析可以看到,Activity启动时会创建一个ViewRootImpl对象,这个ViewRootImpl非常重要,WindowManager通过ViewRootImplDecorView起联系。并且,View的绘制流程都是由ViewRootImpl发起的。

发布了49 篇原创文章 · 获赞 81 · 访问量 3万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览