前言
前几篇分析了Measure、Layout、Draw 过程,这三个过程在第一次展示View的时候都会调用。那之后更改了View的属性呢如更改颜色、更换文字内容、更换图片等,还会走这三个过程吗着这个思路,来分析Invalidate/RequestLayout流程。
通过本篇文章,你将了解到:
1、Invalidate 流程
2、RequestLayout 流程
3、Invalidate/RequestLayout 使用场合
4、子线程真不能绘制UI吗
5、postInvalidate 流程
Invalidate 流程
一个小Demo
MyView 默认展示一块红色的矩形区域,暴露给外界的方法:setColor
用以改变绘制的颜色。颜色改变后,需要重新执行onDraw(xx)才能看到改变后的效果,通过invalidate()方法触发onDraw(xx)调用。
接下来看看invalidate()方法是怎么触发onDraw(xx)方法执行的。
invalidate() 调用栈
invalidate顾名思义:使某个东西无效。在这里表示使当前绘制内容无效,需要重新绘制。当然,一般来说常常简单称作:刷新。
invalidate()是View.java 里的方法。
从上可知,当前要刷新的View确定了刷新区域后即调用了父布局的invalidateChild(xx)方法。该方法为ViewGroup里的final方法。
由上可知,在该方法里区分了硬件加速绘制与软件绘制,分别来看看两者区别:
硬件加速绘制分支
如果该Window支持硬件加速,则走下边流程:
onDescendantInvalidated 方法的目的是不断向上寻找其父布局,并将父布局PFLAG_DRAWING_CACHE_VALID 标记清空,也就是绘制缓存清空。
而我们知道,根View的mParent指向ViewRootImpl对象,因此来看看它里面的onDescendantInvalidated()方法:
做个小结:
1、invalidate() 对于支持硬件加速来说,目的就是寻找需要重绘的View。当前View肯定是需要重绘的,继续递归寻找其父布局直至到根View。
2、如果该View需要重绘,则加上PFLAG_INVALIDATED 标记。
3、设置重绘区域。
用图表示硬件加速绘制的invaldiate流程:
做个小结:
1、invalidate() 对于软件绘制来说,目的就是寻找需要重绘的区域。
2、确定重绘的区域在Window里的位置,该区域需要重新绘制。
用图表示软件绘制invalidate流程:
1、不管是硬件加速绘制还是软件绘制,都会设置重绘的矩形区域。对于硬件加速绘制来说,重绘的区域为整个Window的大小。而对于软件绘制则是设置相交的矩形区域。
2、只要重绘区域不为空,那么当开启三大流程时,Draw过程必然被调用。
3、对于硬件加速绘制来说,通过绘制标记控制需要重绘的View,因此当我们调用view.invalidate()时,该view被设置了重绘标记,在Draw过程里该view draw(xx)被调用。当然如果其父布局设置了软件缓存,则其父布局也需要被重绘,父布局下的子布局也需要重绘。
4、对于软件绘制来说,整个ViewTree的Draw过程都会被调用,只是Canvas仅仅绘制重绘区域指定的矩形区域。
可以看出,启用硬件加速绘制可以避免不必要的绘制。
关于硬件加速绘制与软件绘制详细区别,请移步系列文章:
Android 自定义View之Draw过程(上)
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!