CalledFromWrongThreadException is a common error if you tried to send UI events to the UI thread from outside the UI thread.
In this example, there are 3 AsyncTask:
- MyAsyncTask1 update UI element in doInBackground() via publishProgress() & onProgressUpdate(), no error generated.
- MyAsyncTask1 update UI element in doInBackground() directly, error will reported:
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
- MyAsyncTask1 update UI element in doInBackground() by calling runOnUiThread() with Runnable(), no error generated.
MainActivity.java
package com.blogspot.android_er.androidcalledfromwrongthreadexception;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
TextView textView1, textView2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn1 = (Button)findViewById(R.id.button1);
Button btn2 = (Button)findViewById(R.id.button2);
Button btn3 = (Button)findViewById(R.id.button3);
textView1 = (TextView)findViewById(R.id.textview1);
textView2 = (TextView)findViewById(R.id.textview2);
btn1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
new MyAsyncTask1().execute();
}
});
btn2.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
new MyAsyncTask2().execute();
}
});
btn3.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
new MyAsyncTask3().execute();
}
});
}
//No access UI in doInBackground()
//No error
private class MyAsyncTask1 extends AsyncTask<Void, Integer, Void>{
int i;
@Override
protected void onPreExecute() {
i = 0;
textView1.setText("onPreExecute()");
}
@Override
protected void onPostExecute(Void aVoid) {
textView1.setText("onPostExecute");
}
@Override
protected void onProgressUpdate(Integer... values) {
textView1.setText("onProgressUpdate(): " + values[0]);
}
@Override
protected Void doInBackground(Void... params) {
//update UI via publishProgress() & onProgressUpdate()
while(i<10){
publishProgress(i++);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}
//Update UI in background thread
//error caused by CalledFromWrongThreadException!!!
private class MyAsyncTask2 extends MyAsyncTask1{
@Override
protected Void doInBackground(Void... params) {
while(i<10){
//publishProgress(i++);
textView2.setText("doInBackground(): " + String.valueOf(i++));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}
//Update UI via runOnUiThread()
//No error
private class MyAsyncTask3 extends MyAsyncTask1{
@Override
protected Void doInBackground(Void... params) {
while(i<10){
//publishProgress(i++);
runOnUiThread(new Runnable() {
@Override
public void run() {
textView2.setText("doInBackground(): " + String.valueOf(i++));
}
});
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}
}
layout/activity_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="No access UI in doInBackground()"
android:textAllCaps="false" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Update UI in background thread\nCalledFromWrongThreadException"
android:textAllCaps="false" />
<Button
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="runOnUiThread()"
android:textAllCaps="false" />
<TextView
android:id="@+id/textview1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="40dp" />
<TextView
android:id="@+id/textview2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="40dp" />
</LinearLayout>
No comments:
Post a Comment