CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch views

AndroidHandlerAndroid Asynctask

Android Problem Overview


I have an issue with the following error in Android:

> CalledFromWrongThreadException;: Only > the original thread that created a > view hierarchy can touch its views

It appears to happen when I try to update a Textview in my Activity, the call to update the TextView is from within my Activity but I still get the above error.

I have it like this:

onCreate() -sets up the buttons and the text view.

onStateChange() - a listener for notifications about state changes, when this gets notification if changes the TextView to say some different text.

When I get notification of a new text I try to change the TextView as so:

((TextView)findViewById(R.id.title)).setText("Some Text");

But I get the above Error.

From googling it, it appears I should use a handler to change the TextView or maybe use AsyncTask?

Could anyone explain which one would be better to use and why?

EDIT: ADDED CODE SNIPPETS:


	 public void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);
	        
			requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);	

			setContentView(R.layout.my);
	        
			getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.my_title);	

			((TextView)findViewById(R.id.time)).setText("Hello Text");

			
			findViewById(R.id.keyboardimage).setOnClickListener(new OnClickListener() {
	            public void onClick(View v) {
	            	
	            	Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:"));
	        		startActivity(dialIntent);
	        		
	                    dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.FLAG_SOFT_KEYBOARD));
	                    dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));       
	            }
	    });
			
	 }

//CallBacks from running Service

private final ICallDialogActivity.Stub iCallDialogActivity = new ICallDialogActivity.Stub(){

@Override
public void onStateChanged(int callState)
				throws RemoteException {	
			switch(callState){
			case GlobalData.CALL_STATUS_IDLE:
				 
				break;
				
			case GlobalData.CALL_STATUS_DISCONNECTING:
				byeSetup();
				break;
    } 

};

public void byeSetup(){
	    	
	    	((TextView)findViewById(R.id.time)).setText("Bye Text");
	    	
	    	findViewById(R.id.keyboardimage).setOnClickListener(new OnClickListener() {
	            public void onClick(View v) {
	            	//Void the Button
	            }});
}

Android Solutions


Solution 1 - Android

Look like you are on the wrong thread. Try using a Handler to update the GUI on the right thread. See Handling Expensive Operations in the UI Thread example from android.com. Basically you would wrap byeSetup in a Runnable and invoke it with a Handler instance.

Handler refresh = new Handler(Looper.getMainLooper());
refresh.post(new Runnable() {
    public void run()
    {
        byeSetup();
    }
});

Solution 2 - Android

when the change involves to the main thread (UiThread). Use it inside of another Thread to changes any view.

runOnUiThread(new Runnable() {
    @Override
    public void run() {

      // TODO your Code 
        et_Pass.setText("");
    }
});

Solution 3 - Android

Expanding on willcodejavaforfood's answer for clarity & implementation...

I got this to work and below is how I did it. I'm running multiple processing threads in a Service so other solutions that run in Activity don't work, like runOnUiThread(new Runnable() {}...

Put this at the top of your service class so it's accessible everywhere in this class:

Handler handler;

Put this in your service class onCreate method or something that loads on Service main thread

handler= new Handler(Looper.getMainLooper());

Put this inside your additional thread to 'post back' code to get run in UI or service UI (whatevers its called):

handler.post(new Runnable() {
    public void run() {
        playNext(); //or whatever method you want to call thats currently not working
    }
});

Solution 4 - Android

For others, just replace byeSetup(); with your code statements or methods. byeSetup() is a sample method. Hope it will save some of your time.

Solution 5 - Android

Another approach, this time making use of android.os.Message

Have android.os.Handler defined as a field within your activity:

private final Handler myTextHandler = new Handler(new Handler.Callback() {
	@Override
	public boolean handleMessage(Message stringMessage) {
		textView.append((String) stringMessage.obj);
		return true;
	}
});

Then feed it from your other thread like this:

Message stringMessage = Message.obtain(myTextHandler);
stringMessage.obj = "Hello!";
stringMessage.sendToTarget();

Solution 6 - Android

You can use view's inbuilt post method to update contents in other thread like I'm using edit text in kotlin.

address_box.post { address_box.text="my text"}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDonal RaffertyView Question on Stackoverflow
Solution 1 - AndroidwillcodejavaforfoodView Answer on Stackoverflow
Solution 2 - AndroidKeshav GeraView Answer on Stackoverflow
Solution 3 - AndroidKevinView Answer on Stackoverflow
Solution 4 - AndroidJoseph SelvarajView Answer on Stackoverflow
Solution 5 - AndroidJaroslav ZárubaView Answer on Stackoverflow
Solution 6 - AndroidNeroView Answer on Stackoverflow