文章目录
前言
本系列主要是粗浅的分析View的绘制相关的流程,不仅限于View
的onMeasure()
,onLayout()
,onDraw()
方法,还包括了对于ViewRootImpl
,VSync
,Choreographer
相关类的分析
一.ActivityThread
如果需要弄清楚onMeasure()
,onLayout()
,onDraw()
流程,需要先分析ViewRootImpl,而ViewRootImpl
则是在handleResumeActivity
中创建的。
1.1 handleResumeActivity方法
handleResumeActivity方法是ActivityThread里面的方法,启动Activity后会调用。
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// 调用performResumeActivity,最后会调用Activity的onResume方法
// 这里蕴含一个知识点,在onResume中无法获取View的宽高
// 原因是onMeasure之类的方法是在ViewRootImpl里面执行的,ViewRootImpl却是在onResume调用后创建的!
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
if (r == null) {
return;
}
if (mActivitiesToBeDestroyed.containsKey(token)) {
return;
}
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 (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
// 这里面创建了ViewRootImpl
// decor是DecorView,是View树结构的根View
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
//...省略部分代码
}
ViewRootImpl
在wm.addView(decor, l);
里面创建。接下来就需要进入WindowManager
代码内学习了。
1.2 WindowManager
下面给出ViewManager
,WindowManager
,WindowManagerImpl
,WindowManagerGlobal
和ViewRootImpl
的关系图。
ViewManager
,WindowManager
这些都是接口,WindowManagerImpl
可以看作代理类,WindowManagerGlobal
是真正做事的类。
通过上图可以得知ViewRootImpl
像是WindowManager
和View
之间的中间人一样,同时ViewRootImpl
就是通过WindowManagerGlobal
创建的。
代码如下:
// WindowManagerGlobal类
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
//...省略部分代码
// 创建ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
// 关键点,调用ViewRootImpl的setView函数
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
方法:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {
synchronized (this) {
//...省略部分代码
mSoftInputMode = attrs.softInputMode;
mWindowAttributesChanged = true;
mAttachInfo.mRootView = view;
mAttachInfo.mScalingRequired = mTranslator != null;
mAttachInfo.mApplicationScale =
mTranslator == null ? 1.0f : mTranslator.applicationScale;
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken
= panelParentView.getApplicationWindowToken();
}
mAdded = true;
int res;
// 在这个方法中执行绘制流程以及调整时序和接受Vsync信号
requestLayout();
InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
inputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
//...省略部分代码
}
}
2.1 requestLayout方法
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检测线程,看看是不是主线程
checkThread();
mLayoutRequested = true;
// 和Choreographer相关的
scheduleTraversals();
}
}
scheduleTraversals
是一个很重要的方法,用于执行Choreographer
的相关方法。
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
这里最重要的是Choreographer
这个类,该类主要是接受VSync信号及其相关的逻辑处理,下面一章将对该类做粗浅的分析。
总结
通过上面的分析,知道了ViewRootImpl是在onResume调用后创建,继而执行DecorView
的onMeasure()
,onLayout()
,onDraw()
方法,所以我们在onResume中无法获取View的宽高,因为此时还没有对View做测量操作。