我对Android系统如何工作感到困惑,特别是当它更新视图层次结构时。我们都知道除了UI(主)线程之外,不应该从任何线程更新任何视图。甚至当我们尝试这样做时,Android系统会抛出异常。有一天,我试图在我的应用程序中实现自定义进度显示视图。所以我开始使用标准的Java线程和处理程序组合。
令我惊讶的是,我能够从后台线程更新TextView。
令我惊讶的是,我能够从后台线程更新TextView。
new Thread(new Runnable() {
@Override
public void run() {
mTextView.setText("I am " + Thread.currentThread().getName());
}
}).start();
随后我尝试更新其他视图,效果很不错。于是我尝试在后台线程中添加一个睡眠调用。
new Thread(new Runnable() {
@Override
public void run() {
mTextView.setText("Thread : before sleep");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mTextView.setText("Thread : after sleep");
}
}).start();
我预期它会崩溃,并显示以下信息:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
然后,我尝试在循环100次、1000次之前和之后调用setText()方法。当然,应用程序每次都会崩溃,但我能够看到我的textview上的"Before Sleep"文本。
所以我的问题是系统何时检测到某个非UI线程正在尝试更新视图,以及为什么在非UI线程中没有sleep()调用时不起作用?
ViewRootImpl
的细节吗?如果他们说:“不要从非UI线程触摸UI,否则会得到未知结果”,这难道不足够了吗?也许完整的检查会减慢系统速度,也许会使它变得更大?也许他们只是错过了一些需要检查的点?但这真的重要吗?如果您不打算从其他非UI线程更新视图,那就不重要了。 - pskink