Android中为什么非UI线程不能更新UI?
面试官视角
- 是否理解线程安全的概念(中级)
- 是否能够理解UI线程的工作机制(高级)
- 是否熟悉SurfaceView实现高帧率的原理(高级)
题目剖析(非UI线程更新UI)
- UI线程工作机制
- 为什么UI设计成线程不安全的
- 非UI线程一定不能更新UI吗
UI线程是什么?
zygote 生成App进程后 打开ATP (ActivityThread)
ATP执行main函数 main函数里执行Looper.loop()
当loop死循环结束后会抛出异常
主线程如何工作
Handler.dispatchMessage(分发) <- Looper <- Handler.post
Looper->Main Thread -> Looper.loop->Looper
UI为什么不设计成线程安全的
如果UI设计成线程安全的,就必须加锁保证其UI的安全
既然加了锁,那也就会带来一定的开销,因为60针是UI流畅的
最低针,如果加了锁,可能会出现UI的卡顿以及不流畅的因素,带来极差的用户体验,所以UI不设计成线程安全的原因有以下几点
UI具有可变性,甚至是高频可变性
UI对相应时间的敏感性要求UI操作必须高效
UI组件必须批量绘制来保证效率
非UI线程一定不能更新UI吗
非UI线程不能直接更新UI,但是可以间接更新UI
比如我们在非UI线程使用View.postInvalidate更新UI去重新绘制但是有一种情况,比如SurfaceView 可以在非UI线程直接刷新绘制UI
SurfaceView
prepar content -> lockCanvas -> draw -> unLockCanvasAndPost -> prepar content
↑ 整个过程运行在任何一个线程其实是都可以的
它可以实现一个高帧率,因为绘制放在了非UI线程,只要绘制完告诉UI线程显示就可以了,UI线程的压力就会小很多,比如游戏,地图。
本节回顾
- 探讨UI线程或主线程的定义
- 分析Android进程的启动流程
- 分析Looper的工作机制
- 探讨为什么UI不设计成线程安全的
- 给出UI线程的其他存在形式