ViewRootImpl分析
ViewRootImpl是用来指导我们view体系测量、布局、绘制的一个类,当需要重新刷新的时候,ViewRootImpl会负责去申请vsync信号,然后在收到vsync信号后结合wms完成view的测量、布局、绘制。
源码
主流程代码
通过以前wms的学习我们知道ViewRootImpl的创建是发生在WindowManagerGlobal.addView方法中的,那么我们就从WindowManagerGlobal.addView方法开始我们的分析。
- ViewRootImpl的创建过程
- ViewRootImpl.setView方法
setView方法中的requestLayout会去请求重新绘制屏幕内容,当我们主动调用requestLayout、invalidate、启动动画的时候都会走重新绘制屏幕
- 调用了requestLayout后就会走我们熟悉的Choreographer请求vsync信号的过程,当vsync信号拿到后就会回调TraversalRunnable
- 查看TraversalRunnable
- doTraversal
- performTraversals
在performTraversals方法中会依次调用measureHierarchy、performLayout、performDraw方法完成view的测量、布局绘制
performTraversals方法是如何工作的
此处省略一大段SurfaceView的处理逻辑,将来有必要再说
总的来说,在ViewRootImpl来说,SurfaceView的绘制逻辑优先级是高于我们的view体系的,它会在我们的view绘制之前先执行,并且拥有自己的绘制线程。
performMeasure
- ViewRootImpl.performMeasure
- View.measure
- onMeasure
onMeasure中会设置默认的尺寸
performLayout
小结:ViewRootImpl.performLayout方法会自顶向下进行布局,performLayout方法会进行两次布局,第一次布局会调用DecorView.layout方法。当第一次方法完成后会去布局的请求池去拿最新的请求,如果在布局的过程中有新的布局请求,则我们需要进行重新测量和布局。 当第二次测量和布局完成后,会再次去查看布局请求池中的请求,此时如果又发现了新的请求,则新的请求会等待下一帧到来的时候再去参与到下一帧的绘制中。
performDraw
- ViewRootImpl.performDraw
流程太多细节代码暂时没看那么透,下一步主要的代码在ThreadedRenderer.draw
- ThreadedRenderer.draw
- ThreadedRenderer.updateRootDisplayList
- ThreadedRenderer.updateViewTreeDisplayList
- View.updateDisplayListIfDirty
- View.draw
下图是绘制边缘内容,流程和调用方法与view本身绘制相同,所以后面的代码不贴了
View.requestLayout
其它
某个View.requestLayout快速多次调用,是否会触发多次布局
答:不会
小结:单个View调用requestLayout后,在View.layout方法执行前,无法再次向父类传递mParent.requestLayout请求。吐槽:源码中逻辑运算符操作真难读
是否每次调用View.requestLayout都会 重新测量所有View的尺寸,即:调用所有View.onMeasure方法
答:不会
- View.requestLayout中设置强制布局的标志位
这个标志位只会对当前View有效
- View.measure根据PFLAG_FORCE_LAYOUT标志位判断进行测量
总结:当我们调用某个View.requestLayout的时候会设置一个标志位,当ViewRootImpl收到我们的布局请求后,向下遍历view的时候会走所有子View的measure来测量,这些子View如果没有设置过该标志位,则不会走测量宽度的逻辑。