tvRight.setOnClickListener {
Thread(){
Log.e("yyyyy", "是否主线程:${Looper.myLooper() == Looper.getMainLooper()}")
tvRight.text = "我是谁"
}.start()
}
上面的代码,算不算是子线程操作 UI,子线程更新 UI 不是会报错的么?那个 ViewRoot 的 checkThread 方法,疑惑的是为什么这里是可以正常运行的,点击按钮后文本可以正常修改文字的
1
nicevar 2019-12-18 11:54:18 +08:00
算,子线程操作 UI 又不是一定会出问题,但是不推荐这么干,因为就算运行正常也是个定时炸弹,在某些场景下就会触发直接崩了
|
2
ChenStyle 2019-12-18 17:02:05 +08:00
算是子线程操作了 UI,更新也确实会报错。
不过报错也是看情况,如果在 View 已经完成了初始化,那么肯定会报错。而如果没有在 View 完成初始化下用子线程操作 UI 就不会。 因为 Android 系统碎片化的原因,如果出现了不同的结果,要淡定,换个终端调试…… |
3
winterbells 2019-12-18 18:41:04 +08:00 via Android
用 tvRight.post()
|
4
pdog18 2019-12-18 19:18:51 +08:00
@ChenStyle 也并不死活「完成初始化就肯定会报错啦」
在「非创建 ViewRootImpl 的线程」上更新 UI 不报错的方法有很多: 1. 开启硬件加速时只调用了 invalidate() ,是不会触发到 ViewRootImpl#checkThread() 的,那么肯定是不会报错了。 2. 像你这种 TextView 如果宽高是固定状态,更新 UI 时,也会因为 TextView 内部的机制,没有触发 requestLayout,也不会报错。 3. 还有可以先在「创建 ViewRootImpl 的线程」上通过 requestLayout 让 viewparent 的 flag 进行改变,那么那么在其他线程 requestLayout 也不会递归向上传递到 checkThread 4. 在某个线程中(不一定要主线程)通过 WindowManager 创建 ViewRootImpl,这样在那个线程中更新 UI 也不会有任何问题。 |
5
pdog18 2019-12-18 19:20:09 +08:00 1
像你这代码,你把硬件加速关了,然后 TextView 宽高改成 wrap_content 再点一次,这才 100% 崩。
|