ViewRootImpl入门

基础

        它本身只是一个很平常的类(据说早期的ViewRootImpl是一个Handler,然而api23中它便不是)。
        在Activity#handleResumeActivity()中,会将Activity所关联的PhoneWindow对象中的DecorView传递给ViewRootImpl#setView()中。而由ViewRootImpl对该View进行测量、布局与绘制,同时ViewRootImpl复杂与WMS交互,将Activity的UI给展示出来。总结一下,它的作用就是:
        1,为View进行填充,即将Activity#setContentView()生成的干瘪的View树给真正的绘制出来。
        2,与WMS进行沟通,管理要显示的界面。

构造函数

        ActivityThread#handleResumeActivity()->WindowManagerImpl#addView()->WindowManagerGlobal#addView()->ViewRootImpl(view.getContext(),Display)。

        构造函数中会将第一个参数赋值给ViewRootImpl的全局变量mContext。handleResumeActivity传入的View对象是Window#mDecor,所以view.getContext()返回的就是DecorView所指的Activity实例。

        择一部分构造函数中的代码如下:

        mWindowSession = WindowManagerGlobal.getWindowSession();
        mWindow = new W(this);
        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);

        第一句mWindowSession赋值为WindowManagerGlobal.getWindowSession(),其返回值为一个Session对象,Session的实例化在WMS进程中进行的,本应该中有一个Session的代理对象,所以可以通过Session主要调用WMS中一些方法。

        第二、三句中的W继承于IWindow.Stub,后者继承于Binder又实现了IWindow接口,因此这个W是可以IPC的。第三句中将mWindow赋值给了View.AttachInfo中的mWindow对象,将mWindowSession赋值给了mSession变量。

setView

        与构造函数调用时机相同,并且View参数也相同。所以ViewRootImpl中的mView指的是该ViewRootImpl指依赖的Activity中的DecorView。因此它可以通过调用mView来绘制一个Acitivity组件的UI。

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                //略
                requestLayout();
                //略
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } 
                //略
            }
        }
    }

        而requestLayout->scheduleTraversals()->Choreographer#postCallback()->……->postCallbackDelayedInternal()->scheduleFrameLocked()->scheduleFrameLocked(),它发一个what为MSG_DO_FRAME的msg->doFrame()。
        在这个过程中,有必要跟踪一下scheduleTraversals()的参数,在postCallbackDelayedInternal()之前,都是正常传递的。postCallbackDelayedInternal()如下:

    private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {//前两个参数就是scheduleTraversals()中的参数,token为Null,delayMills为0
        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
            //上一步将三个参数封装成CallbackRecord对象,并通过队列存储
            if (dueTime <= now) {//由于delayMills为0,所以走这一步
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }

到doFrame()时,有这么一句话:

            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
其中第一个参数就是scheduleTraversals()的第一个参数,而doCallBacks()中又会调用CallbackRecord#run()。
        public void run(long frameTimeNanos) {
            if (token == FRAME_CALLBACK_TOKEN) {
                ((FrameCallback)action).doFrame(frameTimeNanos);
            } else {
                ((Runnable)action).run();
            }
        }
        因此到这里之后,会执行scheduleTraversals()中的第二个参数。其第二个参数->doTraversal()->performTraversals(),在这个方法中会执行View的measure,layout与draw。
        到这里,requestLayout()方法执行完毕,其作用就是将View树测量、布局与绘制。
        而在setView()中,还调用了mWindowSession#addToDisplay(),由于mWindowSession是WMS创建的Session对象在本应用中的一个代理,所以mWindowSession#addToDisplay()便会执行到WMS所在的进程中。而Session中该方法很简单,只是添加一个参数(this指代的是Session对象自身)然后传到WMS#addWindow()中。

发布了170 篇原创文章 · 获赞 10 · 访问量 18万+
展开阅读全文

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

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览