我遇到了一个有趣的问题。如果在onCreate/onStart/onResume
activity的方法中编写如下代码:
final Button myButton = (Button)findViewById(R.id.myButton);
final TextView myTextView = (TextView)findViewById(R.id.myTextView);
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
myTextView.setText("Hello text");
}
});
myButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
thread.start();
}
});
或者:
final TextView myTextView = (TextView)findViewById(R.id.myTextView);
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.currentThread().sleep(500);
}
catch (InterruptedException e) {
e.printStackTrace();
}
myTextView.setText("Hello text");
}
});
thread.start();
应该如何,抛出错误
android.view.ViewRoot $ CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
很明显,在这种情况下,我必须更新 ui-thread 中的视图 (Handler, AsyncTask, runOnUiThread, view.post).
但是如果你在另一个线程中更新视图没有延迟(没有睡眠调用或没有通过按下按钮启动线程),则不会抛出异常。
final TextView myTextView = (TextView)findViewById(R.id.myTextView);
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
myTextView.setText("Hello text");
}
});
thread.start();
谁能告诉我为什么会有这样的行为?
更新:
我学习了Android的源码,得出以下结论。Nandeesh写下了真相。初始化视图时调用View的dispatchAttachedToWindow(AttachInfo info, int visibility)方法,该方法初始化mAttachInfo字段。mAttachInfo 对象具有 mViewRootImpl 字段。如果为 null,getViewRootImpl 将返回为 null:
public ViewRootImpl getViewRootImpl() {
if (mAttachInfo != null) {
return mAttachInfo.mViewRootImpl;
}
return null;
}
ViewRootImpl 包含 checkThread 方法。它比较线程:创建视图的线程和请求视图更新的线程。
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
因此,如果视图未初始化,则没有检查和更改不会引发异常。