To get Android AsyncTask to return a result use a callback method (Observer pattern) by following these steps.
- Define a constructor for our async class which extends AsyncTask (we’re required to subclass/extend AsyncTask for use). Let’s call our AsyncTask class MyAsyncTask.
- Constructor parameter takes a class which will handle the AsyncTask result. Usually an Activity or Fragment, but could be a Robolectric Unit Test class for example.
- Declare a member variable/private field to hold the handling Activity/Fragment/Test. We’ll call it ResultListener. The constructor will assign its parameter input to this member variable.
- Declare an Interface within MyAsyncTask. Let’s call it ResultListener
- ResultListener defines a single method that our handling class must implement. Let’s name the method handleAsyncResult and in this case it’s going to take a single boolean as an input parameter.
- In onPostExecute, call our listener class handler method, supplying a value to the input parameter as appropriate for the outcome of doInBackground.
Here’s a concrete example of an Android AsyncTask returning a result:
public class MyAsyncTask<T> extends AsyncTask<T, Void, Boolean> {
private final String TAG = this.getClass().getName();
ResultListener listener;
public interface ResultListener {
void handleAsyncResult(boolean result);
}
WebProxy proxy;
public MyAsyncTask(ResultListener listener) {
this.listener = listener;
}
@Override
protected Boolean doInBackground(T... params) {
// do interesting long running things here, Network, database, etc.
Log.i(TAG, String.format("doInBack: sending %s via Retrofit", params.getClass().getName()));
return true;
}
@Override
protected void onPostExecute(Boolean success) {
listener.handleAsyncResult(success);
}
}
As a bonus this AsyncTask uses a Type parameter <T> as input, so it can handle different input types for the AsyncTask.execute(input). This will make your AsyncTask more reusable and easy to extend for future use.
When MyAsyncTask completes doInBackground, it will pass a boolean to onPostExecute which we’re going to send along to our handling class through listener.handleAsyncResult(success).
Within our handling class (supplied to our AsyncTask constructor) we’ll need to do two things:
- Make our class implement our Interface by adding “implements MyAsyncTask.ResultListener” after the class name.
- Define a method within our handling class with a signature that matches MyAsyncTask.ResultListener.
Here’s an example for our implementing class:
public class Test implements MyAsyncTask.ResultListener {
private boolean asyncResult;
@Override
public void handleAsyncResult(boolean result) {
asyncResult = result;
}
@Test
public void firstAsyncTest() throws Exception {
MyAsyncTask<Checkin> myTask = new MyAsyncTask<>(this);
myTask.execute(someArrayOfTypeT);
assertThat(asyncResult).isTrue();
}
}