子线程中更新UI会报错的那个方法:
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:8358)
void checkThread() { if(mThread!= Thread.currentThread()) { throw newCalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); }}
当访问UI时,ViewRootImpl会调用checkThread方法去检查当前访问UI的线程是哪个,如果不是UI线程则会抛出异常,这是没问题的。但是为什么一开始在MainActivity的onCreate方法中创建一个子线程访问UI,程序还是正常能跑起来呢?
ViewRootImpl的创建在onResume方法回调之后,而我们一开篇是在onCreate方法中创建了子线程并访问UI,在那个时刻,ViewRootImpl是没有创建的,无法检测当前线程是否是UI线程,所以程序没有崩溃一样能跑起来,而之后修改了程序,让线程休眠了200毫秒后,程序就崩了。很明显200毫秒后ViewRootImpl已经创建了,可以执行checkThread方法检查当前线程。
那为什么Google要规定不能在子线程中不能更新UI呢:
首先UI线程(mainThread)并不是线程安全的,这样如果子线程修改UI容易数据错乱,如果做到线程安全的话,这样做是很低效的。其次谷歌推荐如果子线程需要修改UI可以使用handler,这样的队列设也是考虑到并发,效率的体现。为什么 android 会设计成只有创建 ViewRootImpl 的原始线程才能更改 UI 呢?这就要说到 Android 的单线程模型了,因为如果支持多线程修改 View 的话,由此产生的线程同步和线程安全问题将是非常繁琐的,所以 Android 直接就定死了,View 的操作必须在创建它的 UI 线程,从而简化了系统设计。有没有可以在其他非原始线程更新 UI 的情况呢?有,SurfaceView 就可以在其他线程更新UI。