Tuesday, February 12, 2019

Implementing Async Tasks in Android

keywords: background thread, asynchronous tasks

In an Android app when we need to interact with external resources that may potentially take time such as to fetch data from external API or database, we would like the main UI to remain interactive and block the UI thread from functioning while long-running processes are active.  Also note that by default, network task is not allowed to run in UI thread in Android.


If the main thread is used in fetching external data, then the main UI will not remain interactive while the data is being fetched and may show abnormal behavior if the data fetching process encounters an exception. In this case, the android's asynchronous task becomes handy especially for updating the portion of the UI using background threads.

An asynchronous task is one of the several ways to offload the work of main thread to some background thread. While AsyncTask is not the only option, but it is a simple and quite a common option.

To get started, I would like to visit Google's developer's page that contains information on the AsyncTask at https://developer.android.com/reference/android/os/AsyncTask review some content related to implementing AsyncTasks.

The AsyncTask class is an abstract class. The implementation usually is the subclass of the class that runs on UI thread. The implementation of the AsyncTask, i.e., the subclass, will override at least one method and often two methods.

When an asynchronous task is executed, the task goes through 4 steps  as described in the Android Developers page at (https://developer.android.com/reference/android/os/AsyncTask):

  1. onPreExecute(), invoked on the UI thread before the task is executed. This step is used to set up the task, for instance by making the spinner visible in the user interface. 
  2. doInBackground(Params...), invoked on the background thread immediately after onPreExecute()finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use topublishProgress(Progress...) publish one or more units of progress. These values are published on the UI thread, in the steponProgressUpdate(Progress...).
  3. onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress... step. The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
  4. onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
I am going to go over the code to illustrate the working mechanism. The code is from the capstone project that I did for my Android Nano-degree Program at Udacity. The full code is available at https://github.com/benktesh/Capstone-Project. In this demo, I am using a lightweight version of the code as shown in the code block below:

The class NetworkQueryTask implemented as a subclass of MainActivity and this class extends the Android AsyncTask abstract class. The implementation can be defined as below:  

     private class NetworkQueryTask extends AsyncTask<T1, T2, T3> {...}


The T1, T2, and T3 are datatypes of parameters and each of them has some specific meaning. 

The task defined above can be executed as below:

     new NetworkAsyncTask().execute(param1);

The param1 is of the same type as the type of T1.  

The MainActivity runs on UI thread. The 'onCreate(..)' method does setting up the UI. The setting up involves creating adapters for recycler view and so on and finally calls a LoadView(). The LoadView() method executes AsyncTask to fetch the data from the network and update the adapter of the view.

In doing so, we create a subclass NetworkQueryTask that extends form AsyncTask. The class takes three parameters, string, Void and ArrayList<Stock>.  A stock is a simple class to store information about Stock. As soon as the process starts, we want the spinner to be visible that we can do in the doInBackground(..)  method.


In the task above, the three parameters denote the type of input parameters used for doInBackground(T1 param1), onProgressUpdate(T2 param2)and onPostExecute(T3 param3). When the doInBackground(..) step finishes execution, the param3 will be the output of the doInBackground(..) step and will become an input to the onPostExecute(param3) method. 

The subclass in general overrides at least one method, most often, doInBackground(..) method and also a second method, i.e., onPostExecute(). The onProgressUpdate and onPreExecute() methods are optional and can be skipped. Thus, if there is nothing to be done regarding the progress update, then there is no need for overriding onProgressUpdate and then param2 can be of type Void in the class definition itself. For example, suppose there is a need to pass a string parameter to doInBackground() and no need for an onProgressUpdate() method and the onPostExecute() method takes a string parameter, then the class definition would look like below: 

    private class NetworkQueryTask extends AsyncTask<String, Void, String> {...}


Therefore, we can say that the three parameters respectively represent input for doInBackground(), input to onProgressUpdate(), and input to onPostExecute(). The parameter type for output of doInBackground() is same as the input to onPostExectute(). Also, if the async task is to function as fire and forget such as trigger something, then all the parameters can be void. For example, the definition of the subclass, in this case, would look like the following:

     private class NetworkQueryTask extends AsyncTask<Void, Void, Void> {...}

and the above class is executed as below:

     new NetworkAsyncTask().execute();

AsyncTasks are not aware of the other activities in the app and therefore must be handled correctly when the activity is destroyed. Therefore, AsycnTask is not suitable for long running operations because if the app is in the background and when Android terminates the app that called the AsyncTask, the AsyncTask does not get killed and we have to manage the process of what to do with the results of the AsycTask. Thus, AsyncTasks are useful in fetching data that is not long running. There are other alternatives to AyscTask which are IntentServices, Loader, and JobScheduler and many Java-based implementations.

A youtube video on with code demonstration is available at https://youtu.be/Yxg_janIavw