V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
enjoyee
V2EX  ›  Android

各位大佬,问个关于子线程操作 UI 的问题

  •  
  •   enjoyee · 2019-12-18 11:46:21 +08:00 · 9940 次点击
    这是一个创建于 1827 天前的主题,其中的信息可能已经有所发展或是发生改变。
    tvRight.setOnClickListener {
          Thread(){
            Log.e("yyyyy", "是否主线程:${Looper.myLooper() == Looper.getMainLooper()}")
            tvRight.text = "我是谁"
          }.start()
        }
    

    上面的代码,算不算是子线程操作 UI,子线程更新 UI 不是会报错的么?那个 ViewRoot 的 checkThread 方法,疑惑的是为什么这里是可以正常运行的,点击按钮后文本可以正常修改文字的

    5 条回复    2019-12-18 19:20:09 +08:00
    nicevar
        1
    nicevar  
       2019-12-18 11:54:18 +08:00
    算,子线程操作 UI 又不是一定会出问题,但是不推荐这么干,因为就算运行正常也是个定时炸弹,在某些场景下就会触发直接崩了
    ChenStyle
        2
    ChenStyle  
       2019-12-18 17:02:05 +08:00
    算是子线程操作了 UI,更新也确实会报错。
    不过报错也是看情况,如果在 View 已经完成了初始化,那么肯定会报错。而如果没有在 View 完成初始化下用子线程操作 UI 就不会。
    因为 Android 系统碎片化的原因,如果出现了不同的结果,要淡定,换个终端调试……
    winterbells
        3
    winterbells  
       2019-12-18 18:41:04 +08:00 via Android
    pdog18
        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 也不会有任何问题。
    pdog18
        5
    pdog18  
       2019-12-18 19:20:09 +08:00   ❤️ 1
    像你这代码,你把硬件加速关了,然后 TextView 宽高改成 wrap_content 再点一次,这才 100% 崩。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5440 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 08:54 · PVG 16:54 · LAX 00:54 · JFK 03:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.