一。讨论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),取消掉这个线程。