从非 UI 线程逐行更新 TextView(通过setText()
旧行到新行)的片段:
TextView mLog;
final static String ONE_LINER;
// Condition 1: update from loopless thread
new Thread(new Runnable() {
@Override
public void run() {
mLog.append(ONE_LINER);
}
}).start();
// Condition 2: update from thread with Looper
HandlerThread handlerThread = new HandlerThread();
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
mLog.append(ONE_LINER);
}
};
handler.sendEmptyMessage();
代码执行会导致具有不同堆栈跟踪的CalledFromWrongThreadException(请检查下面的“Stacktrace #1”和“Stacktrace #2”)。在这两种变体下(从普通的无循环线程或从内部有 Looper 的HandlerThread更新视图)异常抛出并不精确——事件不会在每次通过工作线程更新 UI 后准确发生。
有没有人想过为什么具有以下调用例程的系统行为(在相同的输入条件下)不是持久的?
Stacktrace #1(频率:高;大多数时候)
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7900)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1207)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:5424)
at android.view.View.invalidateInternal(View.java:13884)
at android.view.View.invalidate(View.java:13848)
at android.view.View.invalidate(View.java:13832)
at android.widget.TextView.updateAfterEdit(TextView.java:8918)
at android.widget.TextView.handleTextChanged(TextView.java:8943)
at android.widget.TextView$ChangeWatcher.onTextChanged(TextView.java:11623)
at android.text.SpannableStringBuilder.sendTextChanged(SpannableStringBuilder.java:1037)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:563)
at android.text.SpannableStringBuilder.append(SpannableStringBuilder.java:286)
at android.text.SpannableStringBuilder.append(SpannableStringBuilder.java:34)
at android.widget.TextView.append(TextView.java:4454)
at android.widget.TextView.append(TextView.java:4441)
Stacktrace #2(频率:罕见;捕获一次)
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7900)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1170)
at android.view.View.requestLayout(View.java:20043)
at android.view.View.requestLayout(View.java:20043)
at android.view.View.requestLayout(View.java:20043)
at android.view.View.requestLayout(View.java:20043)
at android.view.View.requestLayout(View.java:20043)
at android.view.View.requestLayout(View.java:20043)
at android.view.View.requestLayout(View.java:20043)
at android.widget.TextView.checkForRelayout(TextView.java:8024)
at android.widget.TextView.setText(TextView.java:4959)
at android.widget.TextView.setText(TextView.java:4786)
at android.widget.TextView.append(TextView.java:4451)
at android.widget.TextView.append(TextView.java:4441)
注意:
- 没有错误“只有创建视图层次结构的原始线程可以触摸它的视图”当视图更新时没有延迟说明并没有完全涵盖问题(仅“Stacktrace #2”)。
- 操作系统:安卓6.0。