一 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:这里给ActivityThread的消息队列设置一个同步屏障器,就是将绘制UI的任务作为一个异步消息来执行,我们通常理解的handler消息其实是普通的同步消息,即使执行完一个才会执行下一个消息,异步消息则不同,如果是设置了同步屏障器,那么handler只会执行异步消息,同步消息会被屏蔽。通常我们会把中断消息、事件消息等较为重要的Message设置为异步消息,以保证系统能够尽早处理这些消息
- 注释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()到底做了什么?