Accessibility content change on non UI thread future Android versions will throw an exception

@@ -7889,9 +7889,14 @@ public final class ViewRootImpl implements ViewParent, 7889 7889 7890 7890 @Override 7891 7891 public void run() { 7892 - // mSource may be changed in calls below. 7892 + // Protect against re-entrant code and attempt to do the right thing in the case that 7893 + // we're multithreaded. 7893 7894 View source = mSource; 7894 7895 mSource = null; 7896 + if (source == null) { 7897 + Log.e(TAG, "Accessibility content change has no source"); 7898 + return; 7899 + } 7895 7900 // The accessibility may be turned off while we were waiting so check again. 7896 7901 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 7897 7902 mLastEventTimeMillis = SystemClock.uptimeMillis();

@@ -7908,6 +7913,22 @@ public final class ViewRootImpl implements ViewParent, 7908 7913 } 7909 7914 7910 7915 public void runOrPost(View source, int changeType) { 7916 + if (mHandler.getLooper() != Looper.myLooper()) { 7917 + CalledFromWrongThreadException e = new CalledFromWrongThreadException("Only the " 7918 + + "original thread that created a view hierarchy can touch its views."); 7919 + // TODO: Throw the exception 7920 + Log.e(TAG, "Accessibility content change on non-UI thread. Future Android " 7921 + + "versions will throw an exception.", e); 7922 + // Attempt to recover. This code does not eliminate the thread safety issue, but 7923 + // it should force any issues to happen near the above log. 7924 + mHandler.removeCallbacks(this); 7925 + if (mSource != null) { 7926 + // Dispatch whatever was pending. It's still possible that the runnable started 7927 + // just before we removed the callbacks, and bad things will happen, but at 7928 + // least they should happen very close to the logged error. 7929 + run(); 7930 + } 7931 + } 7911 7932 if (mSource != null) { 7912 7933 // If there is no common predecessor, then mSource points to 7913 7934 // a removed view, hence in this case always prefer the source.

@@ -7924,12 +7945,12 @@ public final class ViewRootImpl implements ViewParent, 7924 7945 if (timeSinceLastMillis >= minEventIntevalMillis) { 7925 7946 removeCallbacksAndRun(); 7926 7947 } else { 7927 - mSource.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 7948 + mHandler.postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 7928 7949 } 7929 7950 } 7930 7951 7931 7952 public void removeCallbacksAndRun() { 7932 - mSource.removeCallbacks(this); 7953 + mHandler.removeCallbacks(this); 7933 7954 run(); 7934 7955 } 7935 7956 }

Fix Android CalledFromWrongThreadException

In this tutorial, we shall learn to fix Android Exception CalledFromWrongThreadException : Only the original thread that created a view hierarchy can touch its views.

You might have come across this error while from a thread you are trying to set some property of a View or extract some property of a View, that belong to UI thread.

An important point to be remembered while trying to do any operations with UI views is that, only UI thread that created a view hierarchy can touch its views.

Following is simple example, where we try to access a TextView (that belong to UI thread) in another thread.

MainActivity.kt

package com.tutorialkart.runonuithreadexample import android.support.v7.app.AppCompatActivity import android.os.Bundle import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // start some dummy thread that is different from UI thread Thread(Runnable { // performing some dummy time taking operation var i=0; while(i<Int.MAX_VALUE){ i++ } // try to touch View of UI thread this.textview_msg.text = "Updated from other Thread" }).start() } }

You might see below exception in Logcat

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7534) at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1200) at android.view.View.requestLayout(View.java:20044)

Following is the line of code that caused this exception

this.textview_msg.text = "Updated from other Thread"

In general, you touched an UI View from another thread, which you should not do without any help.

To fix this error, wrap the code that has to be executed on UI thread in a Runnable instance passed to runOnUiThread() method.

(java.lang.Runnable { this.textview_msg.text = "Updated from other Thread" })

Following is the corrected MainActivity.kt

MainActivity.kt

package com.tutorialkart.runonuithreadexample import android.support.v7.app.AppCompatActivity import android.os.Bundle import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // start some dummy thread that is different from UI thread Thread(Runnable { // performing some dummy time taking operation var i=0; while(i<Int.MAX_VALUE){ i++ } // try to touch View of UI thread (java.lang.Runnable { this.textview_msg.text = "Updated from other Thread" }) }).start() } }

Conclusion

In this Kotlin Android Tutorial, we have learnt how to fix Android Exception CalledFromWrongThreadException : Only the original thread that created a view hierarchy can touch its views.

Why should you avoid to run non

If you put long running work on the UI thread, you can get ANR errors. If you have multiple threads and put long running work on the non-UI threads, those non-UI threads can't inform the user of what is happening.

How can I update my view from other than UI thread?

What I found surprised me as I was able to update a TextView from background thread. new Thread(new Runnable() { @Override public void run() { mTextView. setText("I am " + Thread. currentThread().

How many threads can modify the UI components of Android?

Seven Threading Patterns in Android.

How do you fix only the original thread that created a view hierarchy can touch its views?

To fix this error, wrap the code that has to be executed on UI thread in a Runnable instance passed to runOnUiThread() method.