Article Directory
foreword
This series mainly analyzes the process related to the drawing of View, not limited to the methods View
of , , and also includes the analysis of related classes of ,onMeasure()
onLayout()
onDraw()
ViewRootImpl
VSync
Choreographer
一.ActivityThread
If you need to figure out the process, onMeasure()
you need to analyze ViewRootImpl first, which is created in .onLayout()
onDraw()
ViewRootImpl
handleResumeActivity
1.1 The handleResumeActivity method
The handleResumeActivity method is a method in the ActivityThread, which will be called after the Activity is started.
@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
Created inside wm.addView(decor, l);
. Next, you need to enter WindowManager
the code to learn.
1.2 WindowManager
The relationship diagram of ViewManager
, WindowManager
, WindowManagerImpl
, WindowManagerGlobal
and is given below . , these are interfaces, which can be regarded as proxy classes, which are the classes that actually do things. From the above figure, we can know that it is like the middleman between and , and it is created through . code show as below: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;
}
//...省略部分代码
}
Two. ViewRootImpl
After creating ViewRootImpl
, continue to call setView
the method:
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 method
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 检测线程,看看是不是主线程
checkThread();
mLayoutRequested = true;
// 和Choreographer相关的
scheduleTraversals();
}
}
scheduleTraversals
Is a very important method, Choreographer
related methods for execution.
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
The most important thing here is Choreographer
this class, which mainly accepts the VSync signal and its related logic processing. The following chapter will make a rough analysis of this class.
Summarize
Through the above analysis, we know that ViewRootImpl is created after onResume is called, and then executes the DecorView
method , , so we cannot get the width and height of the View in onResume , because the View has not been measured yet.onMeasure()
onLayout()
onDraw()