Android View#post()源码分析
概述
在 Activity 中,在 onCreate() 和 onResume() 中是无法获取 View 的宽高,可以通过 View#post() 获取 View 的宽高。
onCreate和onResume不能获取View的宽高
Activity 的生命周期都是在 ActivityThread 中,当调用 startActivity() ,最终会调用 ActivityThread#performLaunchActivity()。
// ActivityThread#performLaunchActivity()
// 核心代码:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity activity = null;
java.lang.ClassLoader cl = appContext.getClassLoader();
// 通过反射新建一个Activity
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
try {
if (activity != null) {
// 创建并初始化Window
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.activityConfigCallback,
r.assistToken, r.shareableActivityToken);
r.activity = activity;
if (r.isPersistable()) {
// 回调Activity#onCreate()
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
}
}
return activity;
}
// ActivityThread#handleResumeActivity()
// 核心代码:
public void handleResumeActivity()(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, String reason) {
// 最终会回调Activity#onResume()
if (!performResumeActivity(r, finalStateRequest, reason)) {
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 (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
// 添加View,开始View的操作
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
}
}
说明:Activity 先执行 onCreate(),再执行 onResume(),最后才调用 wm.addView() 将 DecorView 添加到视图中,也就是从这里才开始执行 View 测量布局绘制流程。简单说 View 的流程晚于 onResume()。
post可以获取View的宽高
// View#post()
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
// 如果attachInfo不为null,表示View已经添加到Window,直接通过Handler发送到主线程队列
return attachInfo.mHandler.post(action);
}
// 如果attachInfo为null,表示View未添加到Window,暂存在mRunQueue中
getRunQueue().post(action);
return true;
}
private HandlerActionQueue getRunQueue() {
if (mRunQueue == null) {
mRunQueue = new HandlerActionQueue();
}
return mRunQueue;
}
说明:在 onCreate() 和 onResume() 中调用 View#post(),最终都会调用 getRunQueue().post(action)。
wm.addView(decor, l) 执行流程:
- 调用 WindowManagerImpl#addView()。
- 调用 WindowManagerGlobal#addView()。
- 执行 new ViewRootImpl,创建 root 对象(布局管理器),并在内部创建 mAttachInfo 对象、Handler 对象。
- 调用 ViewRootImpl#setView()。
// ViewRootImpl#setView()
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {
synchronized (this) {
if (mView == null) {
mView = view;
// 请求布局,最终调用ViewRootImpl#performTraversals()
requestLayout();
try {
// 通过Binder调用WMS添加Window
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
mTempControls);
}
}
}
}
// ViewRootImpl#performTraversals()
private void performTraversals() {
final View host = mView;
// 调用View#dispatchAttachedToWindow()分发mAttachInfo
host.dispatchAttachedToWindow(mAttachInfo, 0);
// 测量流程
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// 布局流程
performLayout(lp, mWidth, mHeight);
// 绘制流程
performDraw()
}
// View#dispatchAttachedToWindow()
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
// 执行缓存任务
if (mRunQueue != null) {
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}
}
// HandlerActionQueue#executeActions()
public class HandlerActionQueue {
private HandlerAction[] mActions;
public void executeActions(Handler handler) {
synchronized (this) {
final HandlerAction[] actions = mActions;
for (int i = 0, count = mCount; i < count; i++) {
final HandlerAction handlerAction = actions[i];
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
mActions = null;
mCount = 0;
}
}
}
说明:执行 mRunQueue.executeActions(),会将所有缓存的任务发送到 handler 中,等待主线程执行完 performTraversals() 方法后,就会执行 mActions 中的任务,这时就可以获取到 View 的宽高。
总结
执行流程:
- Activity#onCreate()
- Activity#onResume()
- WindowManagerImpl#addView()
- new ViewRootImpl()
- ViewRootImpl#setView()
- View的测量流程
- View的布局流程
- View的绘制流程
- WMS添加Window
- 获取View的宽高