Swapnil Swapnil - 3 months ago 15
Android Question

Does onPreExecute() and onPostExecute() execute on the UI thread or on the thread from which the AsyncTask has been started?

I have been writing

AsyncTask
's for short background operations in android for quite some time and had a very basic question. If I start an
AsyncTask
from a separate thread and not the main UI thread, would my
onPreExecute()
and
onPostExecute
methods be still called in the UI thread or the thread from which I started the
AsyncTask
. I am curious because I was unable to show a popup inside the
onPreExecute()
method when I started the it from some other thread.

EDIT 2

I tried writing this simple activity to try:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

new Thread(new Runnable() {
@Override
public void run() {
final TestAsyncTask task = new TestAsyncTask();
task.execute();
}
}).start();
}

private class TestAsyncTask extends AsyncTask<Void, Void, Void> {

@Override
protected void onPreExecute() {
super.onPreExecute();
}

@Override
protected Void doInBackground(Void... voids) {
return null;
}

@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(MainActivity.this, "Yo!", Toast.LENGTH_LONG).show();
}
}
}


This runs fine.
But when I run the application with the following code:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

new Thread(new Runnable() {
@Override
public void run() {
final TestAsyncTask task = new TestAsyncTask();
task.execute();
}
}).start();
}

private class TestAsyncTask extends AsyncTask<Void, Void, Void> {

@Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(MainActivity.this, "Yo!", Toast.LENGTH_LONG).show();
}

@Override
protected Void doInBackground(Void... voids) {
return null;
}
}
}


It fails with the following error:

Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()


as one of the lines in the stack trace.

Answer

While docs say that these callbacks execute in main thread - it is not true. onPreExecute() runs synchronously from the executeOnExecutor() i.e. in the thread that starts AsyncTask.

onPostExecute() is always runs in main thread. (it is invoked from finish(), and this happens inside Handler that uses looper of main thread).