Android UI绘制源码解析3 (测量,布局,绘制)

一 UI测量发生在Activity的那个生命周期里?

很多朋友在面试的时候都可能会被问到,在Activity的生命周期方法里我们能不能获取到布局里的view的宽高?其实不了解UI绘制流程的朋友可能就会被问到了,在前面两篇文章里,我们知道了一个app在启动的时候,会先创建Application,其次再创建启动Activity,调用Activity的onCreate()方法,但是UI绘制的逻辑并没有在onCreate()方法里,而在onResume()方法里,接下来我们来看一下当调用了Activity的onCreate()方法之后,源码如何进一步调用onResume()方法的

二 Activity的onResume()方法的调用流程

2.1 回顾Activity执行onCreate()的过程

在上一篇文章里,我们知道了Activty从创建到调用onCreate()的源码调用流程,整个流程里,在AMS里创建事务(ClientTransaction),其次通过AMS提交事务给LifecycleManage,执行scheduleTransaction()方法,在此方法里调用了ClientTransaction的 schedule()方法,在这个方法里调用了Application的schedule()方法,此时实现了跨进程通信,从AMS来到了ActivityThead。在这里通过handle发送消息,将事务(ClientTransaction)传入到事务执行器里(TransactionExecutor)里,在执行器中,会通过for循环依次的执行事务里的回调ClientTransactionItem,接下来的流程就跟创建application的流程一样。

2.2 定位执行Activity的onResume()方法

相信有跟着流程的去看源码的朋友会注意到,在事务执行器中,除了有执行事务的callbac逻辑的executeCallbacks()这个方法,还有一个executeLifecycleState()这个方法,这个方法就是执行onReume()方法的关键

TransactionExecutor.execute()

public void execute(ClientTransaction transaction) {
    
    
    executeCallbacks(transaction);
    executeLifecycleState(transaction);
}

我们来仔细看一下这个方法
TransactionExecutor.executeLifecycleState()

 private void executeLifecycleState(ClientTransaction transaction) {
    
    
 
        final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();    //1
        if (lifecycleItem == null) {
    
    
            // No lifecycle request, return early.
            return;
        }
    
        final IBinder token = transaction.getActivityToken();
        final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);

        if (r == null) {
    
    
            // Ignore requests for non-existent client records for now.
            return;
        }

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

        lifecycleItem.execute(mTransactionHandler, token, mPendingActions); //2
        lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
    }

注释一:这里获取事务ActivityLifecycleItem,这个ActivityLifecycleItem是在事务创建过程里,通过一个标志位来决定是否创建的,我们来跟踪一下代码:
ActivityStackSupervisor.realStartActivityLocked()

   final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
    
    
          r.appToken){
    
    

        //创建启动Activity的事务
                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, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                        profilerInfo));

                // Set desired final state.
                //这里根据andResume标志位创建ResumeActivityItem,至于这个标志位相信看了上一篇的朋友有印象,
                //是通过top == activity进行判断的,意思是当前的置顶的activity此时andResume就是true。属于我们要打开的activity,
                //那么在调用完activity的onCreate()方法之后,自然就会调用了onResume()方法
                final ActivityLifecycleItem lifecycleItem;
                if (andResume) {
    
    
                    lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
                } else {
    
    
                    lifecycleItem = PauseActivityItem.obtain();
                }
                //然后给当前的事务设置生命周期状态
                clientTransaction.setLifecycleStateRequest(lifecycleItem);

                // Schedule transaction.  提交事务
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);


}

所以,最终会调用 ResumeActivityItem.execute()这个方法
ResumeActivityItem.execute()

     @Override
public void execute(ClientTransactionHandler client, IBinder token,
        PendingTransactionActions pendingActions) {
    
    
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
    //client其实就是ActivityThread,ClientTransactionHandler是ActivityThread的父类
    client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
            "RESUME_ACTIVITY");
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}

Ok,到这里就回到了ActivityThread的handleResumeActivity(),是不是很熟悉,没错,这个方法里就执行了调用Activity的onResume()方法的逻辑和UI绘制的逻辑

三 ActivityThread的handleResumeActivity()方法

  @Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
    
    
    
        mSomeActivitiesChanged = true;

       //这里执行调用Activity的onResume()
       //注释1
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);            

        final Activity a = r.activity;

		//  注释二
        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 (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);
                } else {
    
    
                    // The activity will get a callback for this {@link LayoutParams} change
                    // earlier. However, at that time the decor will not be set (this is set
                    // in this method), so no action will be taken. This call ensures the
                    // callback occurs with the decor set.
                    a.onWindowAttributesChanged(l);
                }
            }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
        } else if (!willBeVisible) {
    
    
            if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
            r.hideForNow = true;
        }

        // Get rid of anything left hanging around.
        cleanUpPendingRemoveWindows(r, false /* force */);

        // 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) {
    
    
            if (r.newConfig != null) {
    
    
                performConfigurationChangedForActivity(r, r.newConfig);
                if (DEBUG_CONFIGURATION) {
    
    
                    Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig "
                            + r.activity.mCurrentConfig);
                }
                r.newConfig = null;
            }
            if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);
            WindowManager.LayoutParams l = r.window.getAttributes();
            if ((l.softInputMode
                    & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
                    != forwardBit) {
    
    
                l.softInputMode = (l.softInputMode
                        & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
                        | forwardBit;
                if (r.activity.mVisibleFromClient) {
    
    
                    ViewManager wm = a.getWindowManager();
                    View decor = r.window.getDecorView();
                    wm.updateViewLayout(decor, l);
                }
            }

            r.activity.mVisibleFromServer = true;
            mNumVisibleActivities++;
            if (r.activity.mVisibleFromClient) {
    
    
                r.activity.makeVisible();
            }
        }

        r.nextIdle = mNewActivities;
        mNewActivities = r;
        Looper.myQueue().addIdleHandler(new Idler());
    }

3.1 注释一: performResumeActivity()

我们来看一下performResumeActivity()这个方法
ActivityThread.performResumeActivity()

 @VisibleForTesting
    public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
            String reason) {
    
    
        final ActivityClientRecord r = mActivities.get(token);
           //这里调用了Activity的performResume()方法
            r.activity.performResume(r.startsNotResumed, reason);
    }

Activity.performResume()

final void performResume(boolean followedByPause, String reason) {
    
    
  		//这里调用了Instrumentation的callActivityOnResume()方法
        mInstrumentation.callActivityOnResume(this);

    }

Instrumentation.callActivityOnResume()

public void callActivityOnResume(Activity activity) {
    
    
    activity.mResumed = true;
    activity.onResume();
    
    if (mActivityMonitors != null) {
    
    
        synchronized (mSync) {
    
    
            final int N = mActivityMonitors.size();
            for (int i=0; i<N; i++) {
    
    
                final ActivityMonitor am = mActivityMonitors.get(i);
                am.match(activity, activity, activity.getIntent());
            }
        }
    }
}

Ok,到这里就看到了我们熟悉的代码Activity的onResume()被调用了。在注释二处就是执行UI绘制的流程,所以为什么说,我们要获取到UI的高度,必须在onReume()方法之后才能获取原因。

3.2 注释二

ActviityThread.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);
        if (r == null) {
    
    
            // We didn't actually resume the activity, so skipping any follow-up actions.
            return;
        }

        final Activity a = r.activity;

        if (localLOGV) {
    
    
            Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity
                    + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished);
        }

        final int forwardBit = isForward
                ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

        // If the window hasn't yet been added to the window manager,
        // and this guy didn't finish itself or start another activity,
        // then go ahead and add the window.
        boolean willBeVisible = !a.mStartedActivity;
        if (!willBeVisible) {
    
    
            try {
    
    
                willBeVisible = ActivityManager.getService().willActivityBeVisible(
                        a.getActivityToken());
            } catch (RemoteException e) {
    
    
                throw e.rethrowFromSystemServer();
            }
        }
        if (r.window == null && !a.mFinished && willBeVisible) {
    
    
            //获取当前activity的phonewindow
            r.window = r.activity.getWindow();
            //获取Phonewindow里的mDecorview
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            //获取到activity的WindowManager
            ViewManager wm = a.getWindowManager();
            //获取activity的window的LayoutParams
            WindowManager.LayoutParams l = r.window.getAttributes();
            //把Activity的记录类中的Decorview赋值给activity的mDecor
            a.mDecor = decor;

            if (a.mVisibleFromClient) {
    
    
                if (!a.mWindowAdded) {
    
    
                    a.mWindowAdded = true;
                    //调用ViewManager的addView()方法
                    wm.addView(decor, l);
                }
      }

可以看到,这里调用了ViewManager的addview()方法。不过这个是个接口,跟随源码继承类是WindowManager,真正实现它的是WindowManagerImpl,而WindowManagerImpl并没有真正的实现逻辑,真正的逻辑在WindowManagerGlobal这个类中,流程比较简单,这里就不贴代码了,我们直接来看addview()方法
WindowManagerGlobal.addview()

 public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
    
    
      
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
    
    
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
    
    
            // If there's no parent, then hardware acceleration for this view is
            // set from the application's hardware acceleration setting.
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
    
    
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }

        ViewRootImpl root;
        View panelParentView = null;

  

            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 {
    
    
                root.setView(view, wparams, panelParentView);  //注释1
            } catch (RuntimeException e) {
    
    
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
    
    
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

这个方法也很简单,主要是对传进来的参数做了一些判断和初始化的一些工作,最重要的是ViewRootImpl这个类,我们重点来看一下ViewRootImpl的setView()
ViewRootImpl.setView()

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    
    

                // 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.
                requestLayout();



}

方法里代码很多,我们重点跟踪requestLayout()这个方法

ViewRootImpl.requestLayout()

@Override
public void requestLayout() {
    
    
    if (!mHandlingLayoutInLayoutRequest) {
    
    
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}
void scheduleTraversals() {
    
    
    if (!mTraversalScheduled) {
    
    
        mTraversalScheduled = true;
 
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); // 注释1
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);  //注释2
        if (!mUnbufferedInputDispatch) {
    
    
            scheduleConsumeBatchedInput();
        }
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}
  1. 注释1:这里给ActivityThread的消息队列设置一个同步屏障器,就是将绘制UI的任务作为一个异步消息来执行,我们通常理解的handler消息其实是普通的同步消息,即使执行完一个才会执行下一个消息,异步消息则不同,如果是设置了同步屏障器,那么handler只会执行异步消息,同步消息会被屏蔽。通常我们会把中断消息、事件消息等较为重要的Message设置为异步消息,以保证系统能够尽早处理这些消息
  2. 注释2:这里通过Choreographer类的回调执行mTraversalRunnable这个任务
    我们来看一下mTraversalRunnable这个具体的实现
  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");
        }
		//这个方法真正执行UI measure,layout,Draw的入口
        performTraversals();

        if (mProfile) {
    
    
            Debug.stopMethodTracing();
            mProfile = false;
        }
    }
}
    private void performTraversals() {
    
    
  	 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   	 performLayout(lp, mWidth, mHeight);
	 performDraw();
}

好了,到这里先告一段落,接下来就是UI绘制专题最后一篇,只要来讲讲这三个方法,看一下系统是怎么来测量布局绘画我们的UI的,如果想了解Handler的同步屏障器的,我找到了一个很好的博文
Handler详解3-MessageQueue和异步消息
Android中老生常谈的ViewRootImpl的scheduleTraversals()到底做了什么?

猜你喜欢

转载自blog.csdn.net/qq_39431405/article/details/120547530
今日推荐