外观
用了异步 Inflate,生命周期与界面怎么协调?
标准回答
异步 Inflate 的作用,是把允许在后台创建的布局工作移出主线程,减轻启动关键路径的负担。我在冷启动优化中使用过它,但它不会让 Activity 生命周期等待布局完成。
因此设计时要把“页面处于哪个生命周期”和“布局是否准备好”分开看。布局还没创建完成,页面可能已经 onResume;回调回来时,用户也可能已经退出。结果不能不加判断地附加到界面,必须确认页面和当前加载任务仍然有效,并在正确线程执行附加与 UI 绑定。
它也不是任何布局都可以直接后台创建。自定义控件构造过程如果依赖主线程能力,异步创建可能不适用或发生回退,收益就需要通过实际 Trace 检查。与其把整棵复杂布局无差别异步化,我更关心哪些部分阻塞首屏、哪些部分可以按需加载。
展示上还要保证关键内容的整体性。多个区域完成时间不同,如果每完成一块就立刻显示,可能出现页面一块块冒出来的割裂感。因此性能优化需要同时考虑布局就绪、交互就绪和视觉呈现,不能只追求生命周期回调更早结束。
关键机制
- 主线程更新和附加 View;不是任意自定义控件都能后台构造,回退主线程会影响实际收益。
- 关键首屏先完整呈现,复杂或非必要区域按需准备;不能只追求快亮屏而长期不可交互。
- 处理回调晚到、重复进入、旋转与销毁;只做判空不能替代当前会话和页面有效性判断。
通俗例子
如果用户快速进入再退出,布局创建结束时页面可能已销毁。候选处理是取消可取消工作或忽略过期结果,避免把旧 View 附加到新页面。
追问与回答
为什么页面看起来一块块加载?
因为异步让不同区域在不同时间准备好,如果回调一到就立即显示,用户会看到内容分批出现。解决时先区分关键首屏和非关键区域:关键内容需要一致的呈现策略,非关键区域可以有明确的占位或延后展示。不能为了隐藏分批加载又让主线程阻塞等待全部完成,而是要控制依赖和展示时机。
findViewById、setSelected 能一起放后台吗?
不能把异步创建理解成任意 View 操作都可以后台执行。尤其是已经附加到界面的 View,状态更新要遵守主线程规则。异步结果回调后,应在合适的 UI 阶段完成绑定和状态应用;后台更适合准备数据。是否某个查找操作本身可行,也不能代替对整条调用链线程安全的判断。
易混淆点
“异步导致 onResume 乱序”不准确;系统生命周期照常推进,变化的是内容准备时间。
参考资料
内容来源
- Android 技术札记 · 原条目
project-async