首先,提出一个问题,下面三处打印输出的结果是什么呢?
带着问题思考一下,然后猜测一下输出结果,之后我们再带着问题去探寻源码;
public class MyActivity extends Activity {
private static final String TAG = MyActivity.class.getSimpleName();
private Button mButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = findViewById(R.id.my_button);
// 打印输出日志 1
Log.e(TAG, "打印输出日志 1---> onCreate() 获取View的测量宽度:" + mButton.getWidth());
// 打印输出日志 2
mButton.post(new Runnable() {
@Override
public void run() {
Log.e(TAG, "打印输出日志 2---> onCreate() 中 通过post方法获取View的测量宽度:" + mButton.getWidth());
}
});
}
@Override
protected void onResume() {
super.onResume();
// 打印输出日志 3
Log.e(TAG, "打印输出日志 3---> onResume() 获取View的测量宽度:" + mButton.getWidth());
}
}
这里首先给出一下输出结果,看看给你的答案一致不?
从图上的打印输出,我们可以看到,onCreate() 和 onResume() 中我们是获取不到View的测量值的,在onCreate() 中通过post方法可以获取到View的测量值;
如果心中仍疑惑不解的,那么我们就来带着问题探寻源码吧…
在Activity的 onCreate() 方法中,我们通过 setContentView(R.layout.activity_view_dispatch) 指定了页面的布局,之后我们就可以从我们设置的布局中获取到指定的View。为何我们已经指定了布局,也可以查找到指定的View,确不能获取到指定View的测量值呢?
我们来看一下 Activity#setContentView(@LayoutRes int layoutResID) 都做了些什么?
跟进去查看一下
Activity#setContentView(@LayoutRes int layoutResID):
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
getWindow() 方法返回的是一个抽象类 Window,而在Android源码中的唯一实现是 PhoneWindow,找到 PhoneWindow 查看
PhoneWindow#setContentView(int layoutResID):
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
// 初始化 DecorView
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
......省略代码
}
PhoneWindow#installDecor():
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
// 注释 1
mDecor = generateDecor(-1);
......省略代码
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
// 注释 2
mContentParent = generateLayout(mDecor);
......省略代码
if (decorContentParent != null) {
......省略代码--DecorView的父容器配置icon等
} else {
......省略代码--根据代码设置,是否展示Title
}
......省略代码--设置一些转场动画等属性
}
}
注释 1: 初次加载窗口时,mDecor 为空,则调用 generateDecor(-1) 方法生成一个 DecorView 对象并返回。
PhoneWindow#generateDecor(int featureId):
protected DecorView generateDecor(int featureId) {
......省略代码--判断系统上下文环境Context
return new DecorView(context, featureId, this, getAttributes());
}
该方法很短,就是生成一个 DecorView 对象返回,DecorView extends FrameLayout 不同版本的源码有稍微的区别,低版本 DecorView 是PhoneWindow的内部类,高版本是一个单独的类。
注释 2: 根据条件设置,初始化要加载到 DecorView 中的布局,我们来看看源码
PhoneWindow#generateLayout(DecorView decor):
protected ViewGroup generateLayout(DecorView decor) {
......省略代码
......省略代码--根据各种主题设置默认布局等
int layoutResource;
int features = getLocalFeatures();
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
setCloseOnSwipeEnabled(true);
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = a.getResourceId(
R.styleable.Window_windowActionBarFullscreenDecorLayout,
R.layout.screen_action_bar);
} else {
layoutResource = R.layout.screen_title;
}
} else {
// 默认布局样式,无须任何样式的装饰
layoutResource = R.layout.screen_simple;
}
mDecor.startChanging();
// 将布局解析到 DecorView 中,加载的布局是一个系统内嵌的布局
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
// ID_ANDROID_CONTENT 是 android.R.id.content, 这个 View 是从 DecorView 里面去找的,
// 也就是从系统的 layoutResource 里面找一个id是 android.R.id.content 的一个 FrameLayout,
// 我们在代码中通过 setContentView 载入的布局文件就是添加到这个里面的
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
......省略代码
return contentParent;
}
接下来查看
DecorView#onResourcesLoaded(LayoutInflater inflater, int layoutResource):
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
......省略代码
// 加载系统内嵌的布局文件
final View root = inflater.inflate(layoutResource, null);
if (mDecorCaptionView != null) {
if (mDecorCaptionView.getParent() == null) {
addView(mDecorCaptionView, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mDecorCaptionView.addView(root, new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
// Put it below the color views.
// 将加载的系统布局添加到当前 DecorView 中
addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mContentRoot = (ViewGroup) root;
initializeElevation();
}
该方法的作用就是,将加载的系统内嵌的布局文件,通过 DecorView#addView() 方法添加到当前的 DecorView 里面,DecorView 继承自FrameLayout,所以这里调到的是父类 ViewGroup#addView() 方法。
ViewGroup#addView(View child, int index, LayoutParams params):
public void addView(View child, int index, LayoutParams params) {
......省略代码
// addViewInner() will call child.requestLayout() when setting the new LayoutParams
// therefore, we call requestLayout() on ourselves before, so that the child's request
// will be blocked at our level
// 此处的 requestLayout 是 View 的方法
requestLayout();
invalidate(true);
addViewInner(child, index, params, false);
}
对于看过源码的同学,此时是不是该有疑问了?requestLayout() 和 invalidate(true) 方法刷新界面的时候,不会去重新测量,摆放和绘制View的吗?
结合下图,这里我用大白话来解释一下,平时在开发程序写界面的时候,遇到需要刷新界面展示的时候,我们可以调用 requestLayout() 和 invalidate() 来进行界面布局的重新测量、摆放和重绘。只是这个时候测量重绘事件需要通过一层层调用,最终将事件传递到最顶层的布局,也就是ViewRootImpl中,然后由最顶层的布局一层层的向下传递,这也是Android中View的工作原理。这里不展开说,书上或者很多博客都有讲到View工作原理,有兴趣的童鞋可以自行查看。
回到刚才的问题,我们通过 setContentView() 方法,设置布局,初始化DecorView,然后通过 DecorView 加载所需的系统内嵌布局,然后再将其由 addView() 加入到 DecorView 中,再刷新 View 的视图,只是此时我们调用的 requestLayout() 和 invalidate() 是 View 的方法。而我们平时需要测量重绘界面的时候,最终走到的是顶层的 ViewRootImpl 的 requestLayout() 方法,在 setContentView() 方法调用之后,只是初始化了一些布局,ViewRootImpl 还没有被创建出来,所以此时走不到 ViewRootImpl 的 requestLayout() 方法,也就不会启动 View 的一系列测量绘制流程。因此我们自然就获取不到指定 View 的测量值咯!
那么 ViewRootImpl 是在哪里被创建出来的呢?
我们来看一下 Activity 的启动流程,不详说,不然有点跑题,博文也太长。
我这里就当自己做笔记,把之前看的 9.0 系统的启动流程记录一下,9.0 系统和之前的代码不太一样,我们从 realStartActivityLocked() 这个方法来看,realStartActivityLocked() 之前的流程 9.0 系统之后 和 9.0 系统之前的差不多,从这里之后,变的不一样了
先看一下 9.0 以前的源码
9.0 系统之前 ActivityStackSupervisor#realStartActivityLocked():
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
try {
......省略代码
// 9.0之前是通过进程间通信的,调用 Activity 的 内部类 ApplicationThread 的 scheduleLaunchActivity
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global and
// override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
......省略代码
} catch (RemoteException e) {
......省略代码
}
......省略代码
return true;
}
9.0 之前的系统是通过进程间通信的方式,调用 ActivityThread 的内部类 ApplicationThread 的 scheduleLaunchActivity 方法。之后的方法,熟悉源码的应该都知道吧,发消息,然后由内部类 H 来处理消息,然后走到 handleLaunchActivity() 方法,再走到 performLaunchActivity() 方法等等,不再一一赘述了。
再对比看一下 9.0 之后的源码
9.0 系统之后 ActivityStackSupervisor#realStartActivityLocked():
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
......省略代码
try {
try {
......省略代码
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
......省略代码
} catch (RemoteException e) {
......省略代码
}
} finally {
endDeferResume();
}
......省略代码
return true;
}
9.0 系统之后,这里是创建了一个事务,然后进行事物的调度。mService.getLifecycleManager() 方法返回一个 ClientLifecycleManager 对象,接下来我们需要找到这个类对象,然后查看
ClientLifecycleManager#scheduleTransaction(ClientTransaction transaction):
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
final IApplicationThread client = transaction.getClient();
// 继续调用 ClientTransaction 的 schedule() 方法
transaction.schedule();
if (!(client instanceof Binder)) {
// If client is not an instance of Binder - it's a remote call and at this point it is
// safe to recycle the object. All objects used for local calls will be recycled after
// the transaction is executed on client in ActivityThread.
transaction.recycle();
}
}
该方法很短,里面继续调用 ClientTransaction 的 schedule() 方法
ClientTransaction#schedule() :
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}
这个方法也很简单,这里的 mClient 是 IApplicationThread 类型的,我们需要找到他的实现类,也就是 ActivityThread 的内部类 ApplicationThread,查看他的
ActivityThread#ApplicationThread#scheduleTransaction(ClientTransaction transaction):
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
这里,ActivityThread 中没有 scheduleTransaction() 方法,我们找到他的父类 ClientTransactionHandler,然后查看
ClientTransactionHandler#scheduleTransaction(ClientTransaction transaction):
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
// 发送消息到子类 ActivityThread 的 内部类 H 进行处理,H继承自 Handler
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
ActivityThread#H#handleMessage(Message msg):
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
.......省略代码
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
// Client transactions inside system process are recycled on the client side
// instead of ClientLifecycleManager to avoid being cleared before this
// message is handled.
transaction.recycle();
}
// TODO(lifecycler): Recycle locally scheduled transactions.
break;
......省略代码
}
......省略代码
}
Handler消息处理中,调用了
TransactionExecutor#execute(ClientTransaction transaction):
public void execute(ClientTransaction transaction) {
......省略代码
// 关键代码 1
executeCallbacks(transaction);
// 关键代码 2
executeLifecycleState(transaction);
mPendingActions.clear();
......省略代码
}
execute() 关键代码 1
TransactionExecutor#executeCallbacks(ClientTransaction transaction):
public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
......省略代码--判空操作,日志打印
final IBinder token = transaction.getActivityToken();
ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();
final int finalState = finalStateRequest != null ? finalStateRequest.getTargetState() : UNDEFINED;
// Index of the last callback that requests some post-execution state.
final int lastCallbackRequestingState = lastCallbackRequestingState(transaction);
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
// 遍历获取到 ClientTransactionItem 对象,然后开启事务
final ClientTransactionItem item = callbacks.get(i);
if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);
final int postExecutionState = item.getPostExecutionState();
final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
item.getPostExecutionState());
if (closestPreExecutionState != UNDEFINED) {
cycleToPath(r, closestPreExecutionState, transaction);
}
// 执行 ClientTransactionItem 事务
item.execute(mTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);
if (r == null) {
// Launch activity request will create an activity record.
r = mTransactionHandler.getActivityClient(token);
}
if (postExecutionState != UNDEFINED && r != null) {
// Skip the very last transition and perform it by explicit state request instead.
final boolean shouldExcludeLastTransition =
i == lastCallbackRequestingState && finalState == postExecutionState;
cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);
}
}
}
刚开始看到这里,我也是一脸懵,这是要干嘛哈,点进所有能看的,也没看懂接下来要干嘛?最后我想看看,这个循环遍历拿到的 ClientTransactionItem 是干嘛的?他的 execute() 方法做了什么?
既然是从列表中 getCallbacks() 取出来的,能取那当然就有存的,我们就来找一下,在哪里 addCallback() 进去的吧。
前面我们说过,9.0 系统之后 Activity 的启动流程有了改变,那么还是回到改变比较大的地方重新找找吧,我们回到
ActivityStackSupervisor#realStartActivityLocked():
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
......省略代码
try {
......省略代码
try {
......省略代码
// Create activity launch transaction.
// 创建一个 Activity 的启动事务
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
final DisplayContent dc = r.getDisplay().mDisplayContent;
// 看到这里是不是有点小激动了,找到了addCallback,看到了与启动有点儿关系的类,找到看看吧
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.icicle, r.persistentState, results, newIntents,
dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
r.assistToken));
// Set desired final state.
// 看下面的各个类的名字,我们可以猜测这里是处理和生命周期有关的
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
......省略代码
} catch (RemoteException e) {
......省略代码
}
} finally {
endDeferResume();
}
......省略代码
return true;
}
重看 realStartActivityLocked() 方法,9.0 系统之后改成现在的,创建一个 Activity 的启动事务,并调度事务来进行 Activity 的启动,我们看一下这个事务是如何构建的?
public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
if (instance == null) {
instance = new ClientTransaction();
}
instance.mClient = client;
instance.mActivityToken = activityToken;
return instance;
}
这里通过 ClientTransaction.obtain() 方法,获取到一个 ClientTransaction 对象,方法中可以看到,这里用到了线程池,应该是到线程池中去获取一个可重用的事务,具体代码不跟了,担心越写越多了,跑偏咯!
然后就是给这个获取到事务,赋值一些与启动和生命周期相关的回调事件,至此,我们找到了事务中与启动和生命周期有关的回调是如何添加的。
回到 TransactionExecutor#executeCallbacks(ClientTransaction transaction): 方法中,我们知道了循环遍历拿到的 ClientTransaction 对象是 LaunchActivityItem 类,他实现了抽象类 ClientTransactionItem,并重写其 execute() 方法。
LaunchActivityItem#execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) :
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client, mAssistToken);
// client 的实现类是 ActivityThread
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
到这里,我们终于看到了熟悉的 ActivityThread#handleLaunchActivity() 方法了,但是这里和 9.0 系统之前的代码不一样,之前的代码是执行 ActivityThread#performLaunchActivity() 方法,然后走到 ActivityThread#handleResumeActivity() 方法。现在 9.0 系统之后的代码,ActivityThread#handleLaunchActivity() 方法中,执行了 ActivityThread#performLaunchActivity() 方法之后,没有了 ActivityThread#handleResumeActivity() 方法。
还记得在 ActivityStackSupervisor#realStartActivityLocked() 方法中添加的与 Activity 生命周期有关的回调吗?ActivityLifecycleItem 类,他是一个抽象类,ResumeActivityItem 和 PauseActivityItem 都继承自他。加入之后,他在哪里执行的呢?回到 TransactionExecutor#execute(ClientTransaction transaction): 中的关键代码 2
execute() 关键代码 2
TransactionExecutor#executeLifecycleState(ClientTransaction transaction):
private void executeLifecycleState(ClientTransaction transaction) {
// realStartActivityLocked() 方法中,由于我们是第一次启动,andResume为True
final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
......省略代码--判空操作
final IBinder token = transaction.getActivityToken();
final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
......省略代码--日志打印、判空
// Cycle to the state right before the final requested state.
cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);
// Execute the final transition with proper parameters.
lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}
在 realStartActivityLocked() 方法中,由于我们是第一次启动,andResume为True,所以添加到事务中的是 ResumeActivityItem 对象,接着执行其 execute() 方法
ResumeActivityItem#execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions):
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
// client 的实现类是 ActivityThread,看到了熟悉的方法
client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
"RESUME_ACTIVITY");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
看到了熟悉的方法,跟进查看
ActivityThread#handleResumeActivity():
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
......省略代码--判空操作
final Activity a = r.activity;
......省略代码--日志打印
final int forwardBit = isForward
? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
......省略代码
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;
// 执行到 WindowManagerImpl 的 addView()
// 然后会跳转到 WindowManagerGlobal 的 addView()
wm.addView(decor, l);
}
......省略代码
}
}
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
......省略代码--由于第一次启动,只有添加add操作,暂时用不到更新操作
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
......省略代码
}
主要看一下 addView() 方法做了什么?找到实现类 WindowManagerImpl,看一下 addView() 方法
WindowManagerImpl#addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params):
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
// 继续调用 WindowManagerGlobal 的 addView
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
跟进查看
WindowManagerGlobal#addView():
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
......省略代码--判空、异常等
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
......省略代码
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
......省略代码
// 初始化 ViewRootImpl 的实例
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 {
// 调用 ViewRootImpl#setView 设置 root 布局
// 其中 view 为传下来的 DecorView 对象
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
该方法中,先初始化一个 ViewRootImpl 实例,也即是上面图示的,PhoneWindow的根布局,那么,我们是不是找到了 ViewRootImpl 在哪里实例化的了呢?不容易哈!然后调用 ViewRootImpl#setView() 方法
ViewRootImpl#setView():
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.
// 调用 ViewRootImpl 的 requestLayout()
requestLayout();
......省略代码
}
}
}
ViewRootImpl#requestLayout():
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
// 关键代码,这也是很多博客开始分析View的绘制流程的入口
scheduleTraversals();
}
}
ViewRootImpl#scheduleTraversals():
@UnsupportedAppUsage
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 通过postSyncBarrier()设置Handler消息的同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// Choreographer 通过 postCallback 提交一个任务,mTraversalRunnable是要执行的回调
// 有了同步屏障mTraversalRunnable就会被优先执行
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
mTraversalRunnable 是 TraversalRunnable 类的实例, TraversalRunnable 是一个实现了 Runnable 接口的任务回调类,他的 run() 方法,中会调用 ViewRootImpl#doTraversal() 方法,ViewRootImpl#doTraversal() 方法中 会调用 ViewRootImpl#performTraversals()。
Choreographer 通过 postCallback 提交一个任务,mTraversalRunnable是要执行的回调,有了同步屏障mTraversalRunnable就会被优先执行,至于为何有了同步屏障mTraversalRunnable就会被优先执行?可以查看分析Handler之同步屏障机制与Android的屏幕刷新机制在源码中的应用
ViewRootImpl#performTraversals():
private void performTraversals() {
// cache mView since it is used so much below...
final View host = mView;
mIsInTraversal = true;
......省略代码
if (mFirst || windowShouldResize || insetsChanged ||
viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
mForceNextWindowRelayout = false;
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 performMeasure 测量方法
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// Implementation of weights from WindowManager.LayoutParams
// We just grow the dimensions as needed and re-measure if
// needs be
int width = host.getMeasuredWidth();
int height = host.getMeasuredHeight();
boolean measureAgain = false;
......省略代码
// 由measureAgain判断是否需要再次测量
if (measureAgain) {
// 关注方法 1 performMeasure 测量方法
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
layoutRequested = true;
}
}
} else {
maybeHandleWindowMove(frame);
}
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
// 关注方法 2 performLayout 位置摆放方法
performLayout(lp, mWidth, mHeight);
......省略代码
}
......省略代码
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
if (!cancelDraw) {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
}
mPendingTransitions.clear();
}
// 关注方法 3 performDraw 绘制方法
performDraw();
} else {
......省略代码
}
mIsInTraversal = false;
}
View 的测绘绘制流程就是从 ViewRootImpl#performTraversals() 开始的,而这个方法的调用是在 onResume() 方法之后,所以在 onCreate() 和 onResume() 方法中拿不到 View 的测量值也就很容易理解了吧。
为何打印输出日志2 可以获取到 View 的测量值呢?由于篇幅太长了,留待后面再写吧!
如有不足可以提出,互相交流哈!!!