说到Android系统View的绘制流程,大家一定知道是分为测量(Measure)、布局(Layout)和绘制(Draw)三个阶段,这篇文章主要聊一聊在这三个步骤之前的源码执行流程,页面启动后是怎样通过代码执行这三个方法。
之前看过startActivity启动一个Activity最终都会经过ActivityThread类来调用Activity的生命周期。所以我们就从ActivityThread中调用onResume的performResumeActivity方法开始。
1、ActivityThread类的performResumeActivity方法
首先通过performResumeActivity调用Activity的onResume方法,之前在“四大组件”专栏中分析过这个方法。
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
继续向下看:
ViewManager wm = a.getWindowManager();
此处省略好多行。。。。
wm.addView(decor,l),
这里第一个参数就是DecorView的实例,执行顺序在performResumeActivity后面.
补充一下,此处的wm类型是ViewManager,ViewManager是个接口:
/** Interface to let you add and remove child views to an Activity. To get an instance
* of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
*/
public interface ViewManager
{
/**
* Assign the passed LayoutParams to the passed View and add the view to the window.
* <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
* errors, such as adding a second view to a window without removing the first view.
* <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
* secondary {@link Display} and the specified display can't be found
* (see {@link android.app.Presentation}).
* @param view The view to be added to this window.
* @param params The LayoutParams to assign to view.
*/
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
WindowManager接口继承ViewManager,顺着可以找到WindowManager的实现类WindowManagerImpl。
2、来到WindowManagerImpl类
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
3、进入WindowManagerGlobal类
addView方法最底下:
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, userId);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
这里创建ViewRootImpl并且会调用ViewRootImpl的setView方法,这里传入的view就是上面wm.addView(decor,l)时传入的decorView他也会一直透传到ViewRootImpl的setView方法。
4、ViewRootImpl的setView方法
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
if (mView == null) {
mView = view;
下面省略好多行。。。。
上面的view就是从ActivityThread传递过来的DecorView实例,因此mView 就是DecorView,add方法下面滑油三个比较重要的点:requestLayout()和mInputEventReceiver以及view.assignParent(this)。
4.1 requestLayout调用scheduleTraversals
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
@UnsupportedAppUsage
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
4.2 进入Choreographer类
上面mChoreographer.postCallBack, 这里会调用Choreographer类的postCallBack - postCallBackDelayed - postCallbackDelayedInternal - scheduleFrameLocked
@UnsupportedAppUsage
@TestApi
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
@UnsupportedAppUsage
@TestApi
public void postCallbackDelayed(int callbackType,
Runnable action, Object token, long delayMillis) {
if (action == null) {
throw new IllegalArgumentException("action must not be null");
}
if (callbackType < 0 || callbackType > CALLBACK_LAST) {
throw new IllegalArgumentException("callbackType is invalid");
}
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
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);
}
}
}
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame on vsync.");
}
// If running on the Looper thread, then schedule the vsync immediately,
// otherwise post a message to schedule the vsync from the UI thread
// as soon as possible.
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);
}
}
}
上面scheduleFrameLocked方法通过handler发了MSG_DO_FRAME的msg消息。
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_FRAME:
doFrame(System.nanoTime(), 0);
break;
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
case MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);
break;
}
}
}
handleMessage中doFrame方法调用 doCallbacks,然后调用CallbackRecord
类的run方法 c.run(frameTimeNanos);
5、进入CallbackRecord
private static final class CallbackRecord {
public CallbackRecord next;
public long dueTime;
public Object action; // Runnable or FrameCallback
public Object token;
@UnsupportedAppUsage
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
}
通过((Runnable)action).run()看到是又回到了4.1中 mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);可以看到是返回了ViewRootImpl的TraversalRunnable的实例mTraversalRunnable。
6、返回ViewRootImpl
((Runnable)action).run(); 又调回到ViewRootImpl的TraversalRunnable的run方法调:
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
doTraversal方法调用performTraversals()方法
performTraversals()方法,measure测量、layout布局、draw绘制,都是在这个方法开启的:
预测量
windowSizeMayChange |= measureHierarchy(host, lp, res,
desiredWindowWidth, desiredWindowHeight);
布局窗口
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
控件树测量
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec)
布局控件
performLayout(lp,mWidth,mHeight)
绘制控件
performDraw()
以measure控件树测量为例看看怎样调用到View的measure方法:
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
if (mView == null) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
但是DecorView类没有measure(int widthMeasureSpec, int heightMeasureSpec)方法,因此执行顶级父类View的measure方法:
onMeasure(widthMeasureSpec, heightMeasureSpec);
View的measure方法会调用onMeasure,DecorView中有此方法因此来到DecorView:
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
这里super又会调用父类FrameLayout中的onMeasure方法,方法很长只截取部分:
FrameLayout根据它的MeasureSpec调用measureChildWithMargin方法来对每一个子View进行测量:
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (mMeasureAllChildren || child.getVisibility() != GONE) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
maxWidth = Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
maxHeight = Math.max(maxHeight,
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
childState = combineMeasuredStates(childState, child.getMeasuredState());
if (measureMatchParentChildren) {
if (lp.width == LayoutParams.MATCH_PARENT ||
lp.height == LayoutParams.MATCH_PARENT) {
mMatchParentChildren.add(child);
}
}
}
}
DecorView委托父类对所有子view完成测量。
7、ViewRootImpl的setView方法
再说剩下的两个重要的点,后面再细致的单独分析:
res=mWindowSession.addToDisplayAsUser(),与requestLayout同在setView方法,负责将窗口添加到WMS上,主要通过mWindowSession与WMS进行系统通信
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper()),与requestLayout同在setView方法,View事件输入的接收器,接收来自于系统的事件;
view.assignParent(this),与requestLayout同在setView方法,assignParent方法在View类实现,将ViewRootImpl自己设置为DecorView的parent,所以ViewTree上的Root就是ViewRootImpl。
才疏学浅,如有错误,欢迎指正,多谢。