Android View#post()源码分析
文章目录
- Android View#post()源码分析
- 概述
- onCreate和onResume不能获取View的宽高
- post可以获取View的宽高
- 总结
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();// 通过反射新建一个Activityactivity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);try {if (activity != null) {// 创建并初始化Windowactivity.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添加Windowres = 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的宽高