0

A snippet with updating TextView line-to-line (via setText() old line to new one) from non-UI thread:

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();

Code execution causes CalledFromWrongThreadException with different stacktraces (please, check "Stacktrace #1" and "Stacktrace #2" below). Under both variants (updating View from plain loopless Thread or from HandlerThread which has Looper inside) exception throwing isn't precise -- event doesn't occur exact after each UI update via worker thread.

Does any have an thoughts why the system behaviour with following call routinues (in the same input conditions) isn't persistent?

Stacktrace #1 (frequence: high; most of the times)

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 (frequence: rare; catched once)

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)

Note:

  1. No error “Only the original thread that created a view hierarchy can touch its views” when the view is updated without delay explanation doesn't fully cover the issue (only "Stacktrace #2").
  2. OS: Android 6.0.
Community
  • 1
  • 1
Yehor Nemov
  • 907
  • 2
  • 16
  • 31
  • 1
    Are you asking why TextView would have different code paths called as a result of append? Why would that matter? – alanv Nov 12 '15 at 18:59
  • @alanv the core point of interest is **Why CalledFromWrongThreadException doesn't fire every time incorrect UI updates happen?** Discovering the behaviour origin is valuable in case of further building test on **fail-fast principle** cause in opposite it will lead to unpredictable and hard to reproduce testing results. – Yehor Nemov Nov 13 '15 at 06:14

0 Answers0