美文网首页
android 子线程更新视图

android 子线程更新视图

作者: 奔波儿灞_q | 来源:发表于2020-07-02 13:50 被阅读0次

    首先
    再主线程中弹出dialog,没有问题;

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_ui_test)
            btn.setOnClickListener {
                MyDialog(this).show()
            }
        }
        inner class MyDialog(context: Context) : Dialog(context) {
            override fun onCreate(savedInstanceState: Bundle?) {
                super.onCreate(savedInstanceState)
                setContentView(R.layout.dialog_ui_test)
                btn_cancle.setOnClickListener { cancel() }
                btn_change.setOnClickListener {
                    tv.text = "1 (${tv.text})"
                    Toast.makeText(context, tv.text, Toast.LENGTH_SHORT).show()
                }
            }
        }
    

    第二版,子线程弹dialog
    这个没有弹出dialog,也竟然没有崩溃,之前的报错是
    Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()

      btn.setOnClickListener {
                thread {      // ++
                    MyDialog(this).show()
                }             // ++
            }
    

    第三版,
    子线程通过添加looper.prepare(),Looper.loop(),成功弹出了

    btn.setOnClickListener {
                thread {
                    Looper.prepare()    
                    MyDialog(this).show()
                    Looper.loop()
                }
            }
    

    继续尝试
    在弹出的dialog,尝试主线程修改UI

     val mainHandler = Handler(Looper.getMainLooper())
                btn_change.setOnClickListener {
                    mainHandler.post{
                        tv.text = "1 (${tv.text})"
                        Toast.makeText(context, tv.text, Toast.LENGTH_SHORT).show()
                    }
                }
    

    运行报错,
    Only the original thread that created a view hierarchy can touch its views.
    子线程创建的dialog,然后主线程修改UI就报错了,那么到底是哪个线程可以修改UI呢?报的错误提示只有original thread 可以修改,现在找下original thread
    再修改View,会调用requestLayout,

     android.view.View
     public void requestLayout() {
            ***
            if (mParent != null && !mParent.isLayoutRequested()) {
                mParent.requestLayout();
            }
             ***
        }
    
    android.view.ViewRootImpl
     @Override
        public void requestLayout() {
            if (!mHandlingLayoutInLayoutRequest) {
                checkThread();
                mLayoutRequested = true;
                scheduleTraversals();
            }
        }
     void checkThread() {
            if (mThread != Thread.currentThread()) {
                throw new CalledFromWrongThreadException(
                        "Only the original thread that created a view hierarchy can touch its views.");
            }
        }
     public ViewRootImpl(Context context, Display display) {
            ***
            mThread = Thread.currentThread();
            ***
    }
    

    mThread 是 ViewRootImpl创建时侯初始化的,这个viewRootimple 是dialog 创建时初始化的
    所以这里不可以切换线程,只有再创建viewRootimple的线程才可以修改UI

    要在子线程修改UI 有2个办法:
    1.在onResume之前,可以在非UI线程更新视图,因为这个时候不会发生线程校验;线程校验实在ViewRootImpl中进行的,ViewRootImpl实在onResume之后初始化
    2.ViewRootImpl 直接在子线程初始化,之后就可以在初始化线程进行更新视图;

    相关文章

      网友评论

          本文标题:android 子线程更新视图

          本文链接:https://www.haomeiwen.com/subject/txphqktx.html