「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」
相关文章:
Android View的绘制流程(一)-绘制流程以及Activity视图介绍
Android View的绘制流程(二)-Activity视图-DecorView
Android View的绘制流程(三)-Activity视图-WindowManager
Android View的绘制流程(四)-Activity视图-ViewRootImpl
Android View的绘制流程(五)-Measure
Android View的绘制流程(六)-Layout
Android View的绘制流程(七)-Draw
上一篇文章,介绍了窗口和窗口管理Window和WindowManager,DecorView创建完成后,传递给WindowManager,通过windowManager来管理,最终是通过调用addView方法,实例化了 ViewRootImpl ,同时调用 ViewRootImpl 的 setView 方法来持有了 DecorView。上一篇结尾也说到View 的绘制是由 ViewRootImpl 来负责的,每个应用程序窗口的 DecorView 都有一个与之关联的 ViewRootImpl 对象,这种关联关系是由 WindowManager 来维护的。那么接下来我们介绍ViewRootImpl,是怎么来绘制View的。
ViewRootImpl
先看 ViewRootImpl 的 setView 方法,代码很多,这里截取重要部分
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
......
mAdded = true;
int res; /* = WindowManagerImpl.ADD_OKAY; */
// 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.
requestLayout();
......
}
}
}
上面代码可以看到,使用mView保存了传递过来的DecorView,然后通过requestLayout 方法更新UI
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
绘制UI是在主线程,所以checkThread 主要是做一个校验。接着调用 scheduleTraversals 开始计划绘制了。
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
这里使用到一个同步屏障mTraversalBarrier
同步屏障:Handler 的同步屏障。它的作用是可以拦截 Looper 对同步消息的获取和分发,加入同步屏障之后,Looper 只会获取和处理异步消息,如果没有异步消息那么就会进入阻塞状态。也就是说,对 View 绘制渲染的处理操作可以优先处理。
mTraversalRunnable一个Runnable,最终里面会调用run方法,方法里调用了doTraversal方法,doTraversal字面意思就可以理解,开始View的绘制了:
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
从上面方法可以看出来,该方法内部最终会调用 performTraversals 进行绘制。 performTraversals方法相信大家多少都听说过,这个方法就是用来绘制View的,依次就会调用我们非常熟悉的measure,layout和draw方法了。
// ViewRootImpl 类
private void performTraversals() {
// 这个方法代码非常多,但是重点就是执行这三个方法
// 执行测量
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// 执行布局(ViewGroup)中才会有
performLayout(lp, mWidth, mHeight);
// 执行绘制
performDraw();
}
到此就把activity视图所涉及到重要类都介绍了,剩下的就是View的绘制了,接下来的文章会重点介绍,总结下,如下图:
View的整个绘制流程如上图所示,也就是以上几篇文章介绍的重点,大家可以下载Activity的源码,一层层的进入查看,就会了解这个整体的过程了,源码真是好东西,读懂了源码,可以帮我们解决很多很多问题,下面会介绍View绘制过程中调用的三个重要方法,也是以后我们做自定义View过程中,经常会用到的方法。
以上介绍有不对的地方还请指正,欢迎留言评论。