分析源码找出为何onCreate() 和 onResume() 中获取不到View的宽高值?

首先,提出一个问题,下面三处打印输出的结果是什么呢?
带着问题思考一下,然后猜测一下输出结果,之后我们再带着问题去探寻源码;

public class MyActivity extends Activity {

    private static final String TAG = MyActivity.class.getSimpleName();
    private Button mButton;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mButton = findViewById(R.id.my_button);
        // 打印输出日志 1
        Log.e(TAG, "打印输出日志 1---> onCreate() 获取View的测量宽度:" + mButton.getWidth());
		 // 打印输出日志 2
        mButton.post(new Runnable() {
            @Override
            public void run() {
                Log.e(TAG, "打印输出日志 2---> onCreate() 中 通过post方法获取View的测量宽度:" + mButton.getWidth());
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
         // 打印输出日志 3
        Log.e(TAG, "打印输出日志 3---> onResume() 获取View的测量宽度:" + mButton.getWidth());
    }
}

这里首先给出一下输出结果,看看给你的答案一致不?
在这里插入图片描述
从图上的打印输出,我们可以看到,onCreate() 和 onResume() 中我们是获取不到View的测量值的,在onCreate() 中通过post方法可以获取到View的测量值;

如果心中仍疑惑不解的,那么我们就来带着问题探寻源码吧…
在Activity的 onCreate() 方法中,我们通过 setContentView(R.layout.activity_view_dispatch) 指定了页面的布局,之后我们就可以从我们设置的布局中获取到指定的View。为何我们已经指定了布局,也可以查找到指定的View,确不能获取到指定View的测量值呢?

我们来看一下 Activity#setContentView(@LayoutRes int layoutResID) 都做了些什么?

跟进去查看一下
Activity#setContentView(@LayoutRes int layoutResID):

    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

getWindow() 方法返回的是一个抽象类 Window,而在Android源码中的唯一实现是 PhoneWindow,找到 PhoneWindow 查看
PhoneWindow#setContentView(int layoutResID):

    @Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
        	// 初始化 DecorView
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }
		......省略代码
    }

PhoneWindow#installDecor():

private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
        	// 注释 1
            mDecor = generateDecor(-1);
            ......省略代码
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
        	// 注释 2
            mContentParent = generateLayout(mDecor);
			......省略代码
            if (decorContentParent != null) {
				......省略代码--DecorView的父容器配置icon等
            } else {
                ......省略代码--根据代码设置,是否展示Title
            }
			......省略代码--设置一些转场动画等属性
        }
    }

注释 1: 初次加载窗口时,mDecor 为空,则调用 generateDecor(-1) 方法生成一个 DecorView 对象并返回。

PhoneWindow#generateDecor(int featureId):

protected DecorView generateDecor(int featureId) {
        ......省略代码--判断系统上下文环境Context
        return new DecorView(context, featureId, this, getAttributes());
    }

该方法很短,就是生成一个 DecorView 对象返回,DecorView extends FrameLayout 不同版本的源码有稍微的区别,低版本 DecorView 是PhoneWindow的内部类,高版本是一个单独的类。

注释 2: 根据条件设置,初始化要加载到 DecorView 中的布局,我们来看看源码
PhoneWindow#generateLayout(DecorView decor):

protected ViewGroup generateLayout(DecorView decor) {
    ......省略代码
    ......省略代码--根据各种主题设置默认布局等
    int layoutResource;
    int features = getLocalFeatures();
    if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
        layoutResource = R.layout.screen_swipe_dismiss;
        setCloseOnSwipeEnabled(true);
    } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
        if (mIsFloating) {
            TypedValue res = new TypedValue();
            getContext().getTheme().resolveAttribute(
                R.attr.dialogTitleDecorLayout, res, true);
            layoutResource = res.resourceId;
        } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
            layoutResource = a.getResourceId(
                R.styleable.Window_windowActionBarFullscreenDecorLayout,
                R.layout.screen_action_bar);
        } else {
            layoutResource = R.layout.screen_title;
        }
    } else {
        // 默认布局样式,无须任何样式的装饰
        layoutResource = R.layout.screen_simple;
    }
     
    mDecor.startChanging();
    // 将布局解析到 DecorView 中,加载的布局是一个系统内嵌的布局
    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
    // ID_ANDROID_CONTENT 是 android.R.id.content, 这个 View 是从 DecorView 里面去找的,
    // 也就是从系统的 layoutResource 里面找一个id是 android.R.id.content 的一个 FrameLayout,
    // 我们在代码中通过 setContentView 载入的布局文件就是添加到这个里面的
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

	......省略代码
    return contentParent;
}

接下来查看
DecorView#onResourcesLoaded(LayoutInflater inflater, int layoutResource):

    void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
        ......省略代码
        // 加载系统内嵌的布局文件
        final View root = inflater.inflate(layoutResource, null);
        if (mDecorCaptionView != null) {
            if (mDecorCaptionView.getParent() == null) {
                addView(mDecorCaptionView, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
            }
            mDecorCaptionView.addView(root, new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
        } else {
            // Put it below the color views.
            // 将加载的系统布局添加到当前 DecorView 中
            addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        }
        mContentRoot = (ViewGroup) root;
        initializeElevation();
    }

该方法的作用就是,将加载的系统内嵌的布局文件,通过 DecorView#addView() 方法添加到当前的 DecorView 里面,DecorView 继承自FrameLayout,所以这里调到的是父类 ViewGroup#addView() 方法。

ViewGroup#addView(View child, int index, LayoutParams params):

    public void addView(View child, int index, LayoutParams params) {
		......省略代码
        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
        // therefore, we call requestLayout() on ourselves before, so that the child's request
        // will be blocked at our level
        // 此处的 requestLayout 是 View 的方法
        requestLayout();
        invalidate(true);
        addViewInner(child, index, params, false);
    }

对于看过源码的同学,此时是不是该有疑问了?requestLayout() 和 invalidate(true) 方法刷新界面的时候,不会去重新测量,摆放和绘制View的吗?
结合下图,这里我用大白话来解释一下,平时在开发程序写界面的时候,遇到需要刷新界面展示的时候,我们可以调用 requestLayout() 和 invalidate() 来进行界面布局的重新测量、摆放和重绘。只是这个时候测量重绘事件需要通过一层层调用,最终将事件传递到最顶层的布局,也就是ViewRootImpl中,然后由最顶层的布局一层层的向下传递,这也是Android中View的工作原理。这里不展开说,书上或者很多博客都有讲到View工作原理,有兴趣的童鞋可以自行查看。
回到刚才的问题,我们通过 setContentView() 方法,设置布局,初始化DecorView,然后通过 DecorView 加载所需的系统内嵌布局,然后再将其由 addView() 加入到 DecorView 中,再刷新 View 的视图,只是此时我们调用的 requestLayout() 和 invalidate() 是 View 的方法。而我们平时需要测量重绘界面的时候,最终走到的是顶层的 ViewRootImpl 的 requestLayout() 方法,在 setContentView() 方法调用之后,只是初始化了一些布局,ViewRootImpl 还没有被创建出来,所以此时走不到 ViewRootImpl 的 requestLayout() 方法,也就不会启动 View 的一系列测量绘制流程。因此我们自然就获取不到指定 View 的测量值咯!
在这里插入图片描述
那么 ViewRootImpl 是在哪里被创建出来的呢?
我们来看一下 Activity 的启动流程,不详说,不然有点跑题,博文也太长。
我这里就当自己做笔记,把之前看的 9.0 系统的启动流程记录一下,9.0 系统和之前的代码不太一样,我们从 realStartActivityLocked() 这个方法来看,realStartActivityLocked() 之前的流程 9.0 系统之后 和 9.0 系统之前的差不多,从这里之后,变的不一样了

先看一下 9.0 以前的源码
9.0 系统之前 ActivityStackSupervisor#realStartActivityLocked():

    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
        try {
			......省略代码
			// 9.0之前是通过进程间通信的,调用 Activity 的 内部类 ApplicationThread 的 scheduleLaunchActivity
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    // TODO: Have this take the merged configuration instead of separate global and
                    // override configs.
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profilerInfo);
			......省略代码
        } catch (RemoteException e) {
       		......省略代码
        }
		......省略代码
        return true;
    }

9.0 之前的系统是通过进程间通信的方式,调用 ActivityThread 的内部类 ApplicationThread 的 scheduleLaunchActivity 方法。之后的方法,熟悉源码的应该都知道吧,发消息,然后由内部类 H 来处理消息,然后走到 handleLaunchActivity() 方法,再走到 performLaunchActivity() 方法等等,不再一一赘述了。

再对比看一下 9.0 之后的源码
9.0 系统之后 ActivityStackSupervisor#realStartActivityLocked():

  boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
            boolean andResume, boolean checkConfig) throws RemoteException {
		......省略代码
        try {
            try {
           		......省略代码
                clientTransaction.setLifecycleStateRequest(lifecycleItem);

                // Schedule transaction.
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);
				......省略代码
            } catch (RemoteException e) {
           		......省略代码
            }
        } finally {
            endDeferResume();
        }
		......省略代码
        return true;
    }

9.0 系统之后,这里是创建了一个事务,然后进行事物的调度。mService.getLifecycleManager() 方法返回一个 ClientLifecycleManager 对象,接下来我们需要找到这个类对象,然后查看

ClientLifecycleManager#scheduleTransaction(ClientTransaction transaction):

    void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        final IApplicationThread client = transaction.getClient();
        // 继续调用 ClientTransaction 的 schedule() 方法
        transaction.schedule();
        if (!(client instanceof Binder)) {
            // If client is not an instance of Binder - it's a remote call and at this point it is
            // safe to recycle the object. All objects used for local calls will be recycled after
            // the transaction is executed on client in ActivityThread.
            transaction.recycle();
        }
    }

该方法很短,里面继续调用 ClientTransaction 的 schedule() 方法
ClientTransaction#schedule() :

    public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this);
    }

这个方法也很简单,这里的 mClient 是 IApplicationThread 类型的,我们需要找到他的实现类,也就是 ActivityThread 的内部类 ApplicationThread,查看他的

ActivityThread#ApplicationThread#scheduleTransaction(ClientTransaction transaction):

        @Override
        public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
            ActivityThread.this.scheduleTransaction(transaction);
        }

这里,ActivityThread 中没有 scheduleTransaction() 方法,我们找到他的父类 ClientTransactionHandler,然后查看

ClientTransactionHandler#scheduleTransaction(ClientTransaction transaction):

    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        // 发送消息到子类 ActivityThread 的 内部类 H 进行处理,H继承自 Handler
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }

ActivityThread#H#handleMessage(Message msg):

public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                .......省略代码
                case EXECUTE_TRANSACTION:
                    final ClientTransaction transaction = (ClientTransaction) msg.obj;
                    mTransactionExecutor.execute(transaction);
                    if (isSystem()) {
                        // Client transactions inside system process are recycled on the client side
                        // instead of ClientLifecycleManager to avoid being cleared before this
                        // message is handled.
                        transaction.recycle();
                    }
                    // TODO(lifecycler): Recycle locally scheduled transactions.
                    break;
        		......省略代码
            }
           	......省略代码
        }

Handler消息处理中,调用了
TransactionExecutor#execute(ClientTransaction transaction):

    public void execute(ClientTransaction transaction) {
        ......省略代码
		// 关键代码 1
        executeCallbacks(transaction);
		// 关键代码 2
        executeLifecycleState(transaction);
        mPendingActions.clear();
        ......省略代码
    }

execute() 关键代码 1
TransactionExecutor#executeCallbacks(ClientTransaction transaction):

    public void executeCallbacks(ClientTransaction transaction) {
        final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
        ......省略代码--判空操作,日志打印

        final IBinder token = transaction.getActivityToken();
        ActivityClientRecord r = mTransactionHandler.getActivityClient(token);

        final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();
        final int finalState = finalStateRequest != null ? finalStateRequest.getTargetState() : UNDEFINED;
        // Index of the last callback that requests some post-execution state.
        final int lastCallbackRequestingState = lastCallbackRequestingState(transaction);

        final int size = callbacks.size();
        for (int i = 0; i < size; ++i) {
        	// 遍历获取到 ClientTransactionItem 对象,然后开启事务
            final ClientTransactionItem item = callbacks.get(i);
            if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);
            final int postExecutionState = item.getPostExecutionState();
            final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
                    item.getPostExecutionState());
            if (closestPreExecutionState != UNDEFINED) {
                cycleToPath(r, closestPreExecutionState, transaction);
            }
			// 执行 ClientTransactionItem 事务
            item.execute(mTransactionHandler, token, mPendingActions);
            item.postExecute(mTransactionHandler, token, mPendingActions);
            if (r == null) {
                // Launch activity request will create an activity record.
                r = mTransactionHandler.getActivityClient(token);
            }

            if (postExecutionState != UNDEFINED && r != null) {
                // Skip the very last transition and perform it by explicit state request instead.
                final boolean shouldExcludeLastTransition =
                        i == lastCallbackRequestingState && finalState == postExecutionState;
                cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);
            }
        }
    }

刚开始看到这里,我也是一脸懵,这是要干嘛哈,点进所有能看的,也没看懂接下来要干嘛?最后我想看看,这个循环遍历拿到的 ClientTransactionItem 是干嘛的?他的 execute() 方法做了什么?
既然是从列表中 getCallbacks() 取出来的,能取那当然就有存的,我们就来找一下,在哪里 addCallback() 进去的吧。

前面我们说过,9.0 系统之后 Activity 的启动流程有了改变,那么还是回到改变比较大的地方重新找找吧,我们回到
ActivityStackSupervisor#realStartActivityLocked():

boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
            boolean andResume, boolean checkConfig) throws RemoteException {
		......省略代码
        try {
			......省略代码
            try {
				......省略代码
                // Create activity launch transaction.
                // 创建一个 Activity 的启动事务
                final ClientTransaction clientTransaction = ClientTransaction.obtain(
                        proc.getThread(), r.appToken);

                final DisplayContent dc = r.getDisplay().mDisplayContent;
                // 看到这里是不是有点小激动了,找到了addCallback,看到了与启动有点儿关系的类,找到看看吧
                clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
                        r.icicle, r.persistentState, results, newIntents,
                        dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
                                r.assistToken));
                // Set desired final state.
                // 看下面的各个类的名字,我们可以猜测这里是处理和生命周期有关的
                final ActivityLifecycleItem lifecycleItem;
                if (andResume) {
                    lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
                } else {
                    lifecycleItem = PauseActivityItem.obtain();
                }
                clientTransaction.setLifecycleStateRequest(lifecycleItem);

                // Schedule transaction.
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);
				......省略代码
            } catch (RemoteException e) {
            	......省略代码
            }
        } finally {
            endDeferResume();
        }
		......省略代码
        return true;
    }

重看 realStartActivityLocked() 方法,9.0 系统之后改成现在的,创建一个 Activity 的启动事务,并调度事务来进行 Activity 的启动,我们看一下这个事务是如何构建的?

    public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
        ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
        if (instance == null) {
            instance = new ClientTransaction();
        }
        instance.mClient = client;
        instance.mActivityToken = activityToken;

        return instance;
    }

这里通过 ClientTransaction.obtain() 方法,获取到一个 ClientTransaction 对象,方法中可以看到,这里用到了线程池,应该是到线程池中去获取一个可重用的事务,具体代码不跟了,担心越写越多了,跑偏咯!

然后就是给这个获取到事务,赋值一些与启动和生命周期相关的回调事件,至此,我们找到了事务中与启动和生命周期有关的回调是如何添加的。

回到 TransactionExecutor#executeCallbacks(ClientTransaction transaction): 方法中,我们知道了循环遍历拿到的 ClientTransaction 对象是 LaunchActivityItem 类,他实现了抽象类 ClientTransactionItem,并重写其 execute() 方法。

LaunchActivityItem#execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) :

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mIsForward,
                mProfilerInfo, client, mAssistToken);
        // client 的实现类是 ActivityThread
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

到这里,我们终于看到了熟悉的 ActivityThread#handleLaunchActivity() 方法了,但是这里和 9.0 系统之前的代码不一样,之前的代码是执行 ActivityThread#performLaunchActivity() 方法,然后走到 ActivityThread#handleResumeActivity() 方法。现在 9.0 系统之后的代码,ActivityThread#handleLaunchActivity() 方法中,执行了 ActivityThread#performLaunchActivity() 方法之后,没有了 ActivityThread#handleResumeActivity() 方法。

还记得在 ActivityStackSupervisor#realStartActivityLocked() 方法中添加的与 Activity 生命周期有关的回调吗?ActivityLifecycleItem 类,他是一个抽象类,ResumeActivityItem 和 PauseActivityItem 都继承自他。加入之后,他在哪里执行的呢?回到 TransactionExecutor#execute(ClientTransaction transaction): 中的关键代码 2

execute() 关键代码 2
TransactionExecutor#executeLifecycleState(ClientTransaction transaction):

    private void executeLifecycleState(ClientTransaction transaction) {
    	// realStartActivityLocked() 方法中,由于我们是第一次启动,andResume为True
        final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
		......省略代码--判空操作
        final IBinder token = transaction.getActivityToken();
        final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
		......省略代码--日志打印、判空

        // Cycle to the state right before the final requested state.
        cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);

        // Execute the final transition with proper parameters.
        lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
        lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
    }

在 realStartActivityLocked() 方法中,由于我们是第一次启动,andResume为True,所以添加到事务中的是 ResumeActivityItem 对象,接着执行其 execute() 方法

ResumeActivityItem#execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions):

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
        // client 的实现类是 ActivityThread,看到了熟悉的方法
        client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
                "RESUME_ACTIVITY");
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

看到了熟悉的方法,跟进查看
ActivityThread#handleResumeActivity():

 public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        // TODO Push resumeArgs into the activity for consideration
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
		......省略代码--判空操作

        final Activity a = r.activity;
		......省略代码--日志打印
        final int forwardBit = isForward
                ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
		......省略代码
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            ......省略代码
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    // 执行到 WindowManagerImpl 的 addView()
             		// 然后会跳转到 WindowManagerGlobal 的 addView()
                    wm.addView(decor, l);
                }
                ......省略代码
            }
        } 

        // The window is now visible if it has been added, we are not
        // simply finishing, and we are not starting another activity.
        if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
            ......省略代码--由于第一次启动,只有添加add操作,暂时用不到更新操作
            r.activity.mVisibleFromServer = true;
            mNumVisibleActivities++;
            if (r.activity.mVisibleFromClient) {
                r.activity.makeVisible();
            }
        }
	......省略代码
    }

主要看一下 addView() 方法做了什么?找到实现类 WindowManagerImpl,看一下 addView() 方法

WindowManagerImpl#addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params):

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

跟进查看
WindowManagerGlobal#addView():

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
		......省略代码--判空、异常等
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        ......省略代码

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
			......省略代码
			// 初始化 ViewRootImpl 的实例
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
            // do this last because it fires off messages to start doing things
            try {
            	// 调用 ViewRootImpl#setView 设置 root 布局
             	// 其中 view 为传下来的 DecorView 对象
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

该方法中,先初始化一个 ViewRootImpl 实例,也即是上面图示的,PhoneWindow的根布局,那么,我们是不是找到了 ViewRootImpl 在哪里实例化的了呢?不容易哈!然后调用 ViewRootImpl#setView() 方法
ViewRootImpl#setView():

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
				......省略代码
                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                // 调用 ViewRootImpl 的 requestLayout()
                requestLayout();
                ......省略代码
            }
        }
    }

ViewRootImpl#requestLayout():

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            // 关键代码,这也是很多博客开始分析View的绘制流程的入口
            scheduleTraversals();
        }
    }

ViewRootImpl#scheduleTraversals():

 @UnsupportedAppUsage
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            // 通过postSyncBarrier()设置Handler消息的同步屏障
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            // Choreographer 通过 postCallback 提交一个任务,mTraversalRunnable是要执行的回调
            // 有了同步屏障mTraversalRunnable就会被优先执行
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

mTraversalRunnable 是 TraversalRunnable 类的实例, TraversalRunnable 是一个实现了 Runnable 接口的任务回调类,他的 run() 方法,中会调用 ViewRootImpl#doTraversal() 方法,ViewRootImpl#doTraversal() 方法中 会调用 ViewRootImpl#performTraversals()。

Choreographer 通过 postCallback 提交一个任务,mTraversalRunnable是要执行的回调,有了同步屏障mTraversalRunnable就会被优先执行,至于为何有了同步屏障mTraversalRunnable就会被优先执行?可以查看分析Handler之同步屏障机制与Android的屏幕刷新机制在源码中的应用

ViewRootImpl#performTraversals():

private void performTraversals() {
        // cache mView since it is used so much below...
        final View host = mView;
        mIsInTraversal = true;
        ......省略代码
        
        if (mFirst || windowShouldResize || insetsChanged ||
                viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
            mForceNextWindowRelayout = false;
            
            if (!mStopped || mReportNextDraw) {
                boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
                        (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
                if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
                        || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
                        updatedConfiguration) {
                    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
                    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);

                    // Ask host how big it wants to be
                    // 关注方法 1 performMeasure 测量方法
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

                    // Implementation of weights from WindowManager.LayoutParams
                    // We just grow the dimensions as needed and re-measure if
                    // needs be
                    int width = host.getMeasuredWidth();
                    int height = host.getMeasuredHeight();
                    boolean measureAgain = false;
					......省略代码
					// 由measureAgain判断是否需要再次测量
                    if (measureAgain) {
                    	// 关注方法 1 performMeasure 测量方法
                        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                    }
                    layoutRequested = true;
                }
            }
        } else {
            maybeHandleWindowMove(frame);
        }

        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
        boolean triggerGlobalLayoutListener = didLayout
                || mAttachInfo.mRecomputeGlobalAttributes;
        if (didLayout) {
        	// 关注方法 2 performLayout 位置摆放方法
            performLayout(lp, mWidth, mHeight);
            ......省略代码
        }
        ......省略代码
        boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;

        if (!cancelDraw) {
            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).startChangingAnimations();
                }
                mPendingTransitions.clear();
            }
            // 关注方法 3 performDraw 绘制方法
            performDraw();
        } else {
            ......省略代码
        }
        mIsInTraversal = false;
    }

View 的测绘绘制流程就是从 ViewRootImpl#performTraversals() 开始的,而这个方法的调用是在 onResume() 方法之后,所以在 onCreate() 和 onResume() 方法中拿不到 View 的测量值也就很容易理解了吧。

为何打印输出日志2 可以获取到 View 的测量值呢?由于篇幅太长了,留待后面再写吧!

如有不足可以提出,互相交流哈!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章