Skip to content
阅读进度

setSelected、setMargins、findViewById 要在主线程吗? ​

返回 View 与显示链路 目录

标准回答 ​

Android 的 View UI 通常采用单线程模型。对已接入界面的 View,setSelected、更新布局参数、附加或移除孩子等操作,应在拥有这棵 View 树的 UI 线程执行,普通 Activity 中通常就是主线程。

setMargins 只是修改 LayoutParams 中的字段,本身未必马上触发线程检查。但如果这些参数已经被界面使用,在后台修改仍可能与布局过程竞争;修改后也要通过合适的 setLayoutParams / requestLayout 路径通知界面。没有抛异常不等于线程安全。

findViewById 主要是查找 View 引用,并不属于应当后台化的重活。既然查找的是正在被 UI 线程维护的树,后续通常又要更新 View,直接在 UI 线程完成最清楚。可以把数据读取和计算放后台,再将最终结果投递回主线程。

AsyncLayoutInflater 是受限制的布局创建机制,不能推广成任意 View 都能在后台随意操作。postInvalidate 也只负责投递更新请求,不会保护你对共享字段的所有并发写入。

关键机制 ​

  • 后台处理文件、网络和计算;主线程应用最终 UI 状态,并检查页面或会话是否仍有效。
  • 独立的新数据对象可在后台准备,再安全交接;不要让后台持续修改已发布给 UI 的共享对象。
  • 主线程是执行规则,生命周期是有效性规则;切回主线程后仍要防止更新已经结束的页面。

通俗例子 ​

后台读取设备名称,完成后通过主线程 Handler 或页面状态机制更新 TextView;快速退出时丢弃不再属于当前页面的结果。

追问与回答 ​

用 view.post 包起来就万事大吉吗? ​

它可以安排代码在对应 UI 链路执行,但不自动解决页面已销毁、结果过期或任务积压。还要检查当前页面和任务身份,并避免投递大量细碎更新。线程正确只是必要条件,状态与生命周期仍要正确。

易混淆点 ​

某次后台调用没有异常,只能说明未触发检查,不能证明这种用法受到框架保证。

参考资料 ​

内容来源 ​

用完整回答理解机制,用真实证据解释项目。