Android的Activity界面从何处开始绘制
1.设置WindowManager和DecorView的关系
2.把DecorView加入到WindowManager当中
3.创建了一个ViewRootImpl对象root
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 {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
ViewRootImpl 是顶层视图,当我们调用 view 的 requestLayout 或者 invalidate 最终都会循环调用到 ViewRootImpl 中。在 onCreate 调用流程时,DecorView 中的布局已经创建出来,而 ViewRootImpl 在 onResume 之后才会创建。
setView方法中调用了requestLayout()方法:
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
到这里,好了,界面绘制从这里开始:
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
这里就是要求界面绘制必须在主线程中进行更新mThread就是主线程,所以如果当前运行的线程不是主线程,那么就直接报这个异常
然后就是真正的界面绘制了:
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
最终会调用performTraversals方法,然后就开始View的measure了,在ViewRootImpl中是去measure前面提到的DecordeView
measure阶段
调用performMeasure方法,在performMeasure方法中调用了View的measure方法。
layout阶段
对View进行measure完成之后(measureHierarchy方法)会再执行performLayout(lp, mWidth, mHeight)
draw阶段
draw操作在performTraversals方法里交给performDraw去执行,然后会在调用DecorView的draw方法。
对于ViewGroup来说dispatchDraw就是去绘制子 View,具体实现在drawChild方法:
总结view绘制流程
![](https://img.haomeiwen.com/i8669504/267eb41cb7cb67d4.png)
参考:
https://blog.51cto.com/u_16099278/6900766
https://zhuanlan.zhihu.com/p/596265459
由 View 绘制流程引出的一些常见问题
- onCreate 中子线程更新 UI 为什么不会报错
DecorView 在 onCreate 时就创建好了,那 ViewRootImpl 呢?在 onResume 之后才会报错,如果子线程更新UI执行的时机在 ViewRootImpl 未创建之前,那么更新UI触发的 requestLayout 只会回调到布局的根 ViewGroup 中,他们的 requestLayout 并没有检查线程这一操作。
而在 onResume 之后,ViewRootImpl 的 setView 方法对 DecorView 进行了 assignParent 操作,成为了顶层视图,之后再触发 requestLayout 会进行线程检查。
网友评论