外观
invalidate、requestLayout、postInvalidate 有什么区别?
标准回答
invalidate 表示当前显示内容需要更新,主要触发后续绘制;requestLayout 表示布局需求变了,请框架重新评估测量和位置;postInvalidate 允许把重绘请求投递到 UI 线程,适用于规定的跨线程通知场景。
比如自定义进度条只改变进度颜色或填充长度,外部宽高不变,通常调用 invalidate。字体或内容变化导致控件需要更大空间,则应考虑 requestLayout;如果内容也改变,自定义 setter 还要正确通知绘制更新。
它们都不是“现在立刻把整棵树重新画完”。框架会合并更新,并根据脏状态、约束和缓存决定实际需要执行哪些阶段。也不能把 requestLayout 理解为每个节点必定完整重做三步,或把 invalidate 理解为永远只改几个像素、没有其他成本。
关键机制
- 普通 invalidate 应在 UI 线程调用;postInvalidate 是投递更新请求,不是让 onDraw 在后台执行。
- postInvalidateOnAnimation 将更新与动画帧节奏对齐;它仍不保证某个固定时刻已经展示。
- 系统控件的 setter 往往已包含必要更新;业务不要无条件重复 requestLayout 制造额外工作。
通俗例子
主线程把仪表盘进度从 20 改成 30,再 invalidate;如果还把仪表盘半径需求改大,则连测量需求也改变了。
追问与回答
连续调用十次 invalidate,会立刻画十次吗?
不一定。短时间内的无效化请求可以被合并到后续遍历,框架主要保证最终状态在合适时机更新,不保证每个中间状态都单独形成一帧。如果业务必须按顺序呈现多个状态,应使用帧驱动的动画或状态控制,而不是依靠连着调用 invalidate。
易混淆点
后台调用 postInvalidate 不会自动让你此前对 View 或共享数据的任意修改变得线程安全。
参考资料
内容来源
- Android 技术札记 · 原条目
invalidate-layout