Android UI系统工作流程(一):
这一篇我们从Java层了解一下从Activity创建到视图三步走这个流程中,Framework做了哪些事儿。
Activity的启动流程中,会调用到ActivityThread的handleLaunchActivity,其中关键调用是执行ActivityThread的performLaunchActivity方法,内部完成Activity对象的创建:
try {
// 内部通过Class的newInstance方法创建实例
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
// ...
}
// ...
// 调用Activity的attach方法,完成Activity的绑定工作:
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken);
// 然后,创建完Activity之后,调用onCreate回调
mInstrumentation.callActivityOnCreate(activity, r.state);
// Instrumentation的callActivityOnCreate方法会调用到activity的performCreate方法
而Activity的performCreate会回调到Activity的onCreate完成DecorView的创建和装载操作。
在activity的attach方法中:
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
// 完成Activity的PhoneWindow对象的创建,而这个PhoneWindow持有了WMS
// 给的window token。
mWindow = new PhoneWindow(this, window, activityConfigCallback);
// 而当前线程,即ActivityThread.main方法启动的线程,就是UI线程了
mUiThread = Thread.currentThread();
// 完成一些成员字段的赋值
// ...
}
但是了解过Activity的生命周期应该知道,onCreate的时候,Activity只是属于创建完成,但对于用户是不可见的,用户真正看到Activity的界面长什么样子,是到onResume的时候。对应于ActivityThread的handleResumeActivity方法,其内部首先是调用performResumeActivity方法通知Activity回调onResume生命周期:
public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
String reason) {
final ActivityClientRecord r = mActivities.get(token);
// ...
try {
// ...
r.activity.performResume(r.startsNotResumed, reason);
r.state = null;
r.persistentState = null;
r.setState(ON_RESUME);
// ...
} catch (Exception e) {
// ...
}
return r;
}
和create类似,performResume内部会调用到Activity的onResume回调,通知Activity此时已经处于可见状态。
随后在ActivityThread.handleResumeActivity中:
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
// 获取到Activity的onCreate中装载的DecorView并置为不可见状态
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
// 这里WindowManager是一个继承自ViewManager的接口
// ViewManager定义了往Activity中添加、更新、移除View的接口
// wm的实际实现是WindowManagerImpl
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) {
// 如果decorView还没有添加到wm中,执行添加流程
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
} else {
// ...
}
// ...
}
WindowManagerImpl的addView方法转调到WindowManagerGlobal的addView,其中通过ViewRootImpl.setView完成了ViewRootImpl的创建和将decorView添加到ViewRootImpl中。
关于ViewRootImpl的作用:
-
其一是作为Window和View通信的纽带(比如将touch事件分发到DecorView)。
-
其二是作为绘制过程的大管家,处理View的measure,layout,draw流程。
在ViewRootImpl的setView中,调用到了requestLayout完成第一次layout的调度。
而requestLayout实现如下:
public void requestLayout() {
// 如果已经在处理layout请求了,那么无需重复执行
if (!mHandlingLayoutInLayoutRequest) {
// 确保调用是在主线程
checkThread();
mLayoutRequested = true;
// scheduleTraversals。Android视图系统三大流程的核心API
scheduleTraversals();
}
}
scheduleTravsersals即如其名,完成ViewTree遍历的调度,ViewTree遍历就是执行视图树的measure,layout,draw。
void scheduleTraversals() {
// 如果已经处在调度阶段了,重复调用是没有什么意义的
// 所以重复调用requestLayout也好,invalidate也好,并不会触发View的反复重绘
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 往主线程中发送一个同步屏障消息,屏蔽同步消息的处理
// 因为,UI更新事件处理的优先级一定要高于主线程的一般任务。
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 往Choreographer中发送一个mTraversalRunnable
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
Choreographer作为Android视图系统的重量级嘉宾,如其名,编舞者,如果说Android的动画,交互,绘制等行为,是一支舞蹈,而Choreographer就是编排这些行为的导演。
其在4.1版本之后被增加,用于同步Vsync信号,与Vsync机制配合,统一Android当中的动画,输入,绘制处理时机。
而其postCallback的作用,就是在下一帧执行我们传入的callback,postCallback或者postCallbackDelayed(有点类似于Handler那几个API的味道),都是postCallbackDelayedInternal的封装:
// 下面的action实际上就是Runnable对象
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
// ...
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
// 往mCallbackQueues中添加callback
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
// 如果postCallbackDelay传的delay参数是0
// 那么就是执行scheduleFrameLocked
// 否则就是往主线程消息队列中发送一条what为MSG_DO_SCHEDULE_CALLBACK
// 的异步消息,而对于Handler机制的分析我们也能看到
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
瞅一眼mCallbackQueues,上面调用scheduleTraversals的时候传入的callbackType就是Choreographer.CALLBACK_TRAVERSAL,而本身是一个数组,数组的元素是CallbackQueue(即Callback组成的队列)。
callbackType一共有四种:
// 最高优先级的输入事件类型的callback
public static final int CALLBACK_INPUT = 0;
// 动画更新类型的Callback
public static final int CALLBACK_INSETS_ANIMATION = 2;
// 视图遍历更新类型的Callback
public static final int CALLBACK_TRAVERSAL = 3;
// 在视图遍历回调处理完之后的Callback
public static final int CALLBACK_COMMIT = 4;
在scheduleFrameLocked中:
private void scheduleFrameLocked(long now) {
// 如果当前这一帧已经被调度过了,那么就不要重复调度了,避免浪费的重复工作
if (!mFrameScheduled) {
// 这个标志位会在doFrame中置回false
mFrameScheduled = true;
// 当前系统是否使用了垂直同步,当然是true了
if (USE_VSYNC) {
// 如果调度的线程是主线程,那么就scheduleVsyncLocked
// 否则就往主线程的消息队列中的队列头位置插入
// 一条what为MSG_DO_SCHEDULE_VSYNC的异步消息
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
// 如果没有使用垂直同步,那么就自己计算下一帧的时间了
final long nextFrameTime = Math.max(
mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
}
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
而scheduleVsyncLocked 就是调用mDisplayEventReceiver.scheduleVsync():
public void scheduleVsync() {
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
+ "receiver has already been disposed.");
} else {
nativeScheduleVsync(mReceiverPtr);
}
}
而nativeScheduleVsync底层是向SurfaceFlinger服务注册,注册的对象是DisplayEventReceiver自己,在下一次Vsync信号来到的时候,会调用到DisplayEventReceiver的dispatchVsync方法回调其onVsync回调(但是需要注意,这里是注册一次,回调一次,是不会反复回调的),而DisplayEventReceiver是一个抽象类,前面mDisplayEventReceiver实际是FrameDisplayEventReceiver对象,其onVsync如下:
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
// 仍然是往主线程中发消息,mHandler是FrameHanlder
mTimestampNanos = timestampNanos;
mFrame = frame;
// 注意这里的this,FrameDisplayEventReceiver是实现了
// Runnable接口的
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
而发出去的消息,因为是带了callback的,那么会在Handler进行dispatchMessage的时候,执行callback的run方法,FrameDisplayEventReceiver的run方法如下:
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
doFrame的核心就是执行各类向Choreographer注册的回调:
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}
long intendedFrameTimeNanos = frameTimeNanos;
startNanos = System.nanoTime();
// 计算两次调用doFrame之间的时间差
final long jitterNanos = startNanos - frameTimeNanos;
// 如果时间差超过了一帧的时间,就说明有掉帧行为产生
if (jitterNanos >= mFrameIntervalNanos) {
// 计算掉帧的次数
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
// 而如果掉帧的次数超过了SKIPPED_FRAME_WARNING_LIMIT
// (默认30帧,系统属性可配置)
// 输出日志
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Log.i(TAG, "Skipped " + skippedFrames + " frames! "
+ "The application may be doing too much work on its main thread.");
}
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
+ "which is more than the frame interval of "
+ (mFrameIntervalNanos * 0.000001f) + " ms! "
+ "Skipping " + skippedFrames + " frames and setting frame "
+ "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
}
frameTimeNanos = startNanos - lastFrameOffset;
}
// 如果这里条件成立,可能之前有掉帧行为
// 那么这里就会再次调用scheduleVsyncLocked,等待下一次的Vsync信号。
if (frameTimeNanos < mLastFrameTimeNanos) {
scheduleVsyncLocked();
return;
}
// 这里通常是1,可以通过系统属性进行配置
// 推测是降低刷新率以节省电量消耗的优化
if (mFPSDivisor > 1) {
long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
scheduleVsyncLocked();
return;
}
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
// 开始执行各类callback
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
if (DEBUG_FRAMES) {
final long endNanos = System.nanoTime();
Log.d(TAG, "Frame " + frame + ": Finished, took "
+ (endNanos - startNanos) * 0.000001f + " ms, latency "
+ (startNanos - frameTimeNanos) * 0.000001f + " ms.");
}
}
doCallbacks里边做的核心工作就是去除Runnable类型的各类Callback,然后执行:
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
// ...
final long now = System.nanoTime();
// 取出这一帧内要被处理的所有当前type的callback
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
if (callbacks == null) {
return;
}
// ...
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
// 沿着callback队列,逐个执行
for (CallbackRecord c = callbacks; c != null; c = c.next) {
// ...
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
// 对callback的一些回收工作。
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
而对应scheduleTraversals中,postCallback给Choregrapher的callback就是CALLBACK_TRAVESAL,对应的Runnable是mTraversalRunnable,其run方法调用到doTraversal开始ViewTree遍历:
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// performTraversals
performTraversals();
// ...
}
}
最后来一张图总结一下整个流程:
ViewRootImpl通过调用requestLayout(当然也可以是其它API),会往Choreographer中发送一个mTraversalRunnable的消息,Choreographer之后会通过scheduleVsync,通过IPC机制往SurficeFlinger中注册一个回调,而当下一个Vsync信号到来的时候,SurficeFlinger再通过IPC机制,回调到应用进程的onVsync回调,最终触发ViewRootImpl中performaTraversals的执行,而后便是递归measure,layout,draw的流程,在这个过程中,View可以通过对应的onXXX方法,实现视图的测量,放置和绘制行为。