At a glance guide to AsyncTask in Android Android 21.01.2014

android-market-leader-smartphone.png AsyncTask is an Android mechanism created to help handle long operations that need to report to the UI thread. To take advantage of this class, we need to create a new subclass of AsyncTask and implement its doInBackground(), onProgressUpdate(), and onPostExecute() methods. In other words, we are going to fill in the blanks for what to do in the background, what to do when there’s some progress, and what to do when the task completes.

Time consuming jobs such as big data processing, database or network accessing that run in UI thread may cause an ANR error (application not responding). The best solution to avoid ANR (Application not responding) error is using a worker thread running parallel with UI thread.

Before you start using the AsyncTask class, you'll need to understand the lifecycle compared to running an operation on the main thread.

android_asynctask.png

The first method that is called by an AsyncTask is onPreExecute(). This method runs on the UI thread and is meant for setting up any interface components that need to let the user know that something is happening.

After onPreExecute() has finished, doInBackground(T) is called. The generic parameter here is any information that you need to pass to the method for it to perform its task. For example, if you're writing a task that retrieves JSON from a URL, you would pass the URL to this method as a String. As an operation makes progress in doInBackground(), you can call onProgressUpdate(T) to update your UI (such as a progress bar on the screen). Here the generic is a value representing the progress, such as an Integer.

Once the doInBackground() method has completed, it can return an object that is passed into onPostExecute(T), such as a JSONObject that was downloaded from our initial URL. onPostExecute(T) runs on the UI thread.

The following are the four AsyncTask functions that can be used:

  • doInBackground – This is the main working function. If progress update is necessary, the publishProgress can be called, which will finally leads to the calling of onProgressUpdate. isCancelled() can be used to test the state of thread, so as to do the job properly.
  • onProgressUpdate – This method is invoked by calling publishProgress anytime from doInBackground call this method. UI update should only be done in this function.
  • onPreExecute – This is called before doInBackground.
  • onPostExecute – This is called after doInBackground. Result from doInBackground is passed to this method.

AsyncTask is a template class which takes three type arguments: the first is the type for argument of doInBackground; the second is the type for the argument of onProgressUpdate; the third is the type for the argument onPostExecute. These three functions each have an input argument of vargars type.

Bellow is simple example with AsyncTask. There are LinearLayout with a Button and a WebView. Click on Button will load page to WebView in AsyncTask. Very simple example but it give all "gotcha".

Here is activity_main.xml with LinearLayout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btnLoad"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="loadPage"
        android:text="Load page">
    </Button>

    <WebView
        android:id="@+id/wvPage"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
</LinearLayout>

Following is MainActivity

public class MainActivity extends Activity {
    final Context context = this;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void loadPage(View view) {
        LoadPage task = new LoadPage();
        task.execute(new String[] {"http://proft.me"});
    }

    private class LoadPage extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... urls) {
            WebView wv = (WebView) findViewById(R.id.wvPage);
            wv.loadUrl(urls[0]);
            return null;
        }
        @Override
        protected void onPostExecute(String result) {
            Toast.makeText(MainActivity.this, "Page loaded", Toast.LENGTH_SHORT).show();
        }
    }
}

Following is example of anonymous AsyncTask with simple task

new AsyncTask<Void, Void, Void>() {
    @Override
    protected void onPreExecute() { super.onPreExecute(); }

    @Override
    protected Void doInBackground(Void... params) {
        // task
        GlideApp.get(context).clearDiskCache();
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {}
}.execute();

There is a issue when starting an AsyncTask and then rotating the screen. If you attempt to reference a Context item (such as a View or Activity) after the original Context has been destroyed, an Exception will be thrown. The easiest way around this is to call cancel(true) on your AsyncTask in your Activity or Fragment's onDestroy() method, and then validate that the task hasn't been canceled in onPostExecute(T).

AsyncTask is impractical for some use cases:

  • Changes to device configuration cause problems. When device configuration changes while an AsyncTask is running, for example if the user changes the screen orientation, the activity that created the AsyncTask is destroyed and re-created. The AsyncTask is unable to access the newly created activity, and the results of the AsyncTask aren't published.
  • Old AsyncTask objects stay around, and your app may run out of memory or crash. If the activity that created the AsyncTask is destroyed, the AsyncTask is not destroyed along with it. For example, if your user exits the application after the AsyncTask has started, the AsyncTask keeps using resources unless you call cancel().

When to use AsyncTask:

  • Short or interruptible tasks.
  • Tasks that don't need to report back to UI or user.
  • Low-priority tasks that can be left unfinished.

For all other situations, use AsyncTaskLoader, which is part of the Loader framework.

Useful links