CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch views
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
}});
}
Solution 1:
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:
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:
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:
For others, just replace byeSetup(); with your code statements or methods. byeSetup() is a sample method. Hope it will save some of your time.