从源码分析 Activity 启动的时候 View 是何时且如何显示到屏幕上的
这篇文章的重点通过源码分析 Activity 启动的时候 View 是何时且如何显示到屏幕上的
Activity 启动的生命周期
学习 Android 应该都知道 Activity 启动的生命周期,毕竟刚开始学都是从生命周期入手的
onCreate
onStart
onResume
你虽然知道 Activity 启动的生命周期,但是你是否有疑惑过屏幕上的 View 是何时显示出来的?到底是怎么显示的?
从源码分析 View 是何时且如何显示到屏幕上的
看过 Activity 启动的生命周期源码的,应该对 ResumeActivityItem 都不陌生
ResumeActivityItem 就是在执行 Activity onResume 生命周期的时候 ActivityManagerService 通过 Binder 传给 ActivityThread 的消息
通知 ActivityThread 真正去执行 Activity 的 onResume 方法
android\app\servertransaction\ResumeActivityItem.java
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
"RESUME_ACTIVITY");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
其实最终还是回到了 ActivityThread 里面实现了 handleResumeActivity 方法,这个方法分为了两个步骤
- 真正执行 Activity 的 onResume 方法
- 把根 View 加入到 WindowManager 里面,然后开始渲染展示根 View
android\app\ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
...
// TODO Push resumeArgs into the activity for consideration
// 1. 真正执行 Activity 的 onResume 方法
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
...
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();
...
// 2. 把根 View 加入到 WindowManager 里面,然后开始渲染展示根 View
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
} else { ... }
}
} else if (!willBeVisible) { ... }
...
}
首先看下第一个步骤,performResumeActivity 是如何执行 Activity 的 onResume 方法的
这里很直接,直接调用了 Activity 的 performResume 方法
android\app\ActivityThread.java
public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
String reason) {
...
try {
...
r.activity.performResume(r.startsNotResumed, reason);
r.state = null;
r.persistentState = null;
r.setState(ON_RESUME);
} catch (Exception e) { ... }
return r;
}
下面就是一步步最终调用 Activity 的 onResume 方法
Activity#performResume() --> Instrumentation#callActivityOnResume() --> Activity#onResume()
android\app\Activity.java
final void performResume(boolean followedByPause, String reason) {
performRestart(true /* start */, reason);
mFragments.execPendingActions();
...
mCalled = false;
// mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this);
...
mFragments.dispatchResume();
mFragments.execPendingActions();
onPostResume();
}
android\app\Instrumentation.java
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());
}
}
}
}
android\app\Activity.java
protected void onResume() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
mActivityTransitionState.onResume(this, isTopOfTask());
if (mAutoFillResetNeeded) { ... }
mCalled = true;
}
我们返回前面的第二个步骤
如何把根 View 加入到 WindowManager 里面,然后开始渲染展示根 View
这里面传过来的 view = DecorView, 也就是 Activity 的根 View
android\view\WindowManagerImpl.java
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
最终实现其实都是由 WindowManagerGlobal 做的
- 创建出 ViewRootImpl
- 给 ViewRootImpl 设置具体的 DecorView
android\view\WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
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);
} catch (RuntimeException e) { ... }
}
}
在给 ViewRootImpl 设置具体的 DecorView 的时候,其实就是要做布局的操作了
android\view\ViewRootImpl.java
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.
requestLayout();
...
}
}
}
一步步查看实现 Layout 的地方,Choreographer 编导者是有固定的的回调时间的,通知进行绘制(大概间隔 15ms, 也就是我们常说的 60 帧)
android\view\ViewRootImpl.java
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 里面执行绘制的三个步骤
- Measure
- Layout
- Draw
android\view\ViewRootImpl.java
private void performTraversals() {
...
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. Measure
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
layoutRequested = true;
}
}
} else { ... }
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
// 2. Layout
performLayout(lp, mWidth, mHeight);
...
}
...
if (!cancelDraw && !newSurface) {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
}
mPendingTransitions.clear();
}
// 3. Draw
performDraw();
} else { ... }
mIsInTraversal = false;
}
总结
DecorView 最终显示在屏幕上是在 onResume 阶段做的,但是要晚于 onResume 的操作
DecorView 显示的过程也就是 View 绘制的三个步骤: Measure, Layout, Draw