Android子线程更新View的探索

作者: 墨源为水 | 来源:发表于2016-06-11 18:48 被阅读1147次

    一。讨论android非主线程是否能更新UI呢?

    我们在开发App时,经常会遇到这样的Log崩溃日志

    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views

    很简单的意思:只有创建该view的线程才能操作给view。关于这个问题我先借用别人提出的案例,

    案例一:

    案例二:


    运行以上代码出现的结果是:案例一可以正常运行,案例二出现崩溃现象,其错误原因均是文章开头提出的异常,对于这个结果让前期的我非常困惑,以下我会分析原因:

    (1)崩溃的原因当然是我在非UI线程下调用了setText方法,我依次对setText往下遍历

    Textview.setText->TextView.checkForRelayout->invalidate->ViewGroup.invalidateChild->

    发现导致崩溃的最根本原因是ViewRootImpl.checkThread()方法。

    void checkThread() {

    if (mThread != Thread.currentThread()) {

    throw new CalledFromWrongThreadException(

    "Only the original thread that created a view hierarchy can touch its views.");

    }

    }

    (2)那为什么案例一可以正常运行呢?我们先回顾一下Activity与Fragment生命周期探讨 ,activity是onCreate中进行界面的数据准备,onStart()之后,Activity的界面就对用户可见了。案例一线程开启是在oncreat()且子线程并没有处理复杂的逻辑,所以导致线程开启后setText方法还会是在onCreat生命周期内、案例二很明显setText是在onResume()生命周期内。

    分析:不同生命周期内调用setText()方法其实本质不同,

    1.onCreat生命周期内调用setText,界面不可见,所以不会调用invalidate方法,那就更不会调用checkThread,所以不会崩溃,其实此时的setText方法的含义并没有实现更新view操作。

    2.onResume生命周期内,界面已经可见,任何的更新view的操作,势必都会导致调用invalidate
    来更新view,所以此时在非UI线程下更新view必会崩溃

    综上所述得出结论:非UI线程下不能更新view

    二。为什么google设计非UI线程下不能更新view?

    如果可以并发的更新UI,事实上是 “is not thread safe”的,也就是线程不安全。我们都知道,线程安全问题其实就是,不同的线程对同一块资源的调用。在更新UI的同时,会涉及context资源的调用,所以产生了线程安全问题。

    你足够了解Context吗?

    三。如何在非主线程下更新View操作?

    1.方法一:Handler

    2.方法二:用Activity对象的runOnUiThread方法更新

    3.方法三:View.post(Runnable r)

    这时候你要注意在onPause的时候view.removeCallbacks(runable),取消掉这个线程。


    相关文章

      网友评论

      • 小柯_:三。如何在非主线程下更新View操作?

        这几个方法不都是后面切换回去主线程去更新了嘛

      本文标题:Android子线程更新View的探索

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