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(); } }