Android AsyncTask Example

android.os.Handler and android.os.AsyncTask classes all supports asynchronous task in android. To use Handler, you need to create a new child thread object for each task. When a task is finished, it will send a message to the main thread Handler to update UI components. But when multiple tasks are executed simultaneously, it is not easy to control threads accurately.

The android.os.AsyncTask is introduced in android SDK since version 1.5. It makes android asynchronous task implementation easier. You do not need to create a Handler instance and you also do not need to create and attach asynchronous task thread instance to the handler object.

android-asynctask-process-flow

Table of Contents

1. AsyncTask Definition.

  1. Below is the AsyncTask class definition java code. It is an abstract class that you must extend to create a sub-class to use.
    public abstract class AsyncTask<Params, Progress, Result> { 
              ...
    }
    
    
  2. There are three generic types in the class definition also, they have below meanings.
  3. Params: The input parameter type for asynctask’s execute(Params…params) and doInBackground(Params…params) method input parameter array.
  4. Progress: The input parameter type for the publishProgress(Progress… values) and onProgressUpdate(Progress… values) method input parameter array. When you use publishProgress(Progress… values) method to publish current task progress data, onProgressUpdate(Progress… values) method will be invoked.
  5. Result: Represent the return data type of doInBackground(Params… params) method. It is also the input parameter type of both onPostExecute(Result result) and onCancelled(Result result) method.

2. AsyncTask Methods.

  1. Create a sub-class that extends android.os.AsyncTask. Then you can override it’s methods to implement different purposes.
  2. execute(Params… params): This method is invoked in java code to start the asynchronous task.
  3. void onPreExecute():  Used to do some UI operation before performing background tasks.
  4. String doInBackground(Integer… inputParams): Run immediately after onPreExecute() is completed, it is used to perform more time-consuming operations. This method accepts the input parameters and returns the calculated results. During the execution, you can call publishProgress(Progress… Values) to update the progress information.
  5. void onProgressUpdate(Progress… values): This method will be invoked when executing publishProgress(Progress… Values) method in java code. Generally, we update the UI component’s status such as text, progress percentage in this method.
  6. void onPostExecute(String result):  When the background task is complete, this method will be invoked automatically. Parameter result’s value is just which doInBackground(Params… params) method returned.
  7. void onCancelled(String result): This method will be invoked when AsyncTask’s cancel(boolean cancel) method is invoked.

3. AsyncTask Notes.

  1. Must create AsyncTask instance in UI thread.
  2. Must invoke execute(Params… params) method in UI thread.
  3. The onPreExecute(), doInBackground(Params… params), onProgressUpdate(Progress… values), onPostExecute(Result result) are all callback methods, do not call them by code manually.
  4. Can not update UI component’s data in doInBackground(Params… params) method.
  5. Each AsyncTask instance can run only once, if run one AsyncTask instance twice, there will throw an exception.

4. AsyncTask Example.

If you can not watch the above video, you can see it on the youtube URL https://youtu.be/yC8xfdxfXf0

  1. activity_async_task.xml
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        tools:layout_editor_absoluteY="8dp"
        tools:layout_editor_absoluteX="8dp">
    
        <Button
            android:id="@+id/executeAsyncTaskButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Execute Async Task" />
    
        <Button
            android:id="@+id/cancelAsyncTaskButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Cancel Async Task" />
    
        <ProgressBar
            android:id="@+id/asyncTaskProgressBar"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <TextView
                android:id="@+id/asyncTaskLogTextView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="" />
    
        </ScrollView>
    </LinearLayout>
  2. AsyncTaskActivity.java
    package com.dev2qa.example;
    
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    public class AsyncTaskActivity extends AppCompatActivity {
    
        private final String ASYNC_TASK_TAG = "ASYNC_TASK";
    
        private Button executeAsyncTaskButton;
        private Button cancelAsyncTaskButton;
        private ProgressBar asyncTaskProgressBar;
        private TextView asyncTaskLogTextView;
    
        private MyAsyncTask myAsyncTask;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_async_task);
    
            setTitle("dev2qa.com - AsyncTask Example");
    
            this.executeAsyncTaskButton = (Button)findViewById(R.id.executeAsyncTaskButton);
            this.executeAsyncTaskButton.setEnabled(true);
    
            this.cancelAsyncTaskButton = (Button)findViewById(R.id.cancelAsyncTaskButton);
            this.cancelAsyncTaskButton.setEnabled(false);
    
            this.asyncTaskProgressBar = (ProgressBar)findViewById(R.id.asyncTaskProgressBar);
            this.asyncTaskLogTextView = (TextView)findViewById(R.id.asyncTaskLogTextView);
    
            executeAsyncTaskButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // Need to create a new MyAsyncTask instance for each call,
                    // otherwise there will through an exception.
                    myAsyncTask = new MyAsyncTask();
                    myAsyncTask.execute(Integer.parseInt("10"));
    
                    executeAsyncTaskButton.setEnabled(false);
                    cancelAsyncTaskButton.setEnabled(true);
                }
            });
    
            cancelAsyncTaskButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // Cancel a running task, then MyAsyncTask's onCancelled(String result) method will be invoked.
                    myAsyncTask.cancel(true);
                }
            });
        }
    
        // MyAsyncTask is used to demonstrate async task process.
        private class MyAsyncTask extends AsyncTask<Integer, Integer, String>{
    
            // onPreExecute() is used to do some UI operation before performing background tasks.
            @Override
            protected void onPreExecute() {
                asyncTaskLogTextView.setText("Loading");
                Log.i(ASYNC_TASK_TAG, "onPreExecute() is executed.");
            }
    
            // doInBackground(String... strings) is used to execute background task, can not modify UI component in this method.
            // It return a String object which can be used in onPostExecute() method.
            @Override
            protected String doInBackground(Integer... inputParams) {
    
                StringBuffer retBuf = new StringBuffer();
                boolean loadComplete = false;
    
                try
                {
                    Log.i(ASYNC_TASK_TAG, "doInBackground(" + inputParams[0] + ") is invoked.");
    
                    int paramsLength = inputParams.length;
                    if(paramsLength > 0) {
                        Integer totalNumber = inputParams[0];
                        int totalNumberInt = totalNumber.intValue();
    
                        for(int i=0;i < totalNumberInt; i++)
                        {
                            // First calculate progress value.
                            int progressValue = (i * 100 ) / totalNumberInt;
    
                            //Call publishProgress method to invoke onProgressUpdate() method.
                            publishProgress(progressValue);
    
                            // Sleep 0.2 seconds to demo progress clearly.
                            Thread.sleep(200);
                        }
    
                        loadComplete = true;
                    }
                }catch(Exception ex)
                {
                    Log.i(ASYNC_TASK_TAG, ex.getMessage());
                }finally {
                    if(loadComplete) {
                        // Load complete display message.
                        retBuf.append("Load complete.");
                    }else
                    {
                        // Load cancel display message.
                        retBuf.append("Load canceled.");
                    }
                    return retBuf.toString();
                }
            }
    
            // onPostExecute() is used to update UI component and show the result after async task execute.
            @Override
            protected void onPostExecute(String result) {
                Log.i(ASYNC_TASK_TAG, "onPostExecute(" + result + ") is invoked.");
                // Show the result in log TextView object.
                asyncTaskLogTextView.setText(result);
    
                asyncTaskProgressBar.setProgress(100);
    
                executeAsyncTaskButton.setEnabled(true);
                cancelAsyncTaskButton.setEnabled(false);
            }
    
            // onProgressUpdate is used to update async task progress info.
            @Override
            protected void onProgressUpdate(Integer... values) {
                Log.i(ASYNC_TASK_TAG, "onProgressUpdate(" + values + ") is called");
                asyncTaskProgressBar.setProgress(values[0]);
                asyncTaskLogTextView.setText("loading..." + values[0] + "%");
            }
    
            // onCancelled() is called when the async task is cancelled.
            @Override
            protected void onCancelled(String result) {
                Log.i(ASYNC_TASK_TAG, "onCancelled(" + result + ") is invoked.");
                // Show the result in log TextView object.
                asyncTaskLogTextView.setText(result);
                asyncTaskProgressBar.setProgress(0);
    
                executeAsyncTaskButton.setEnabled(true);
                cancelAsyncTaskButton.setEnabled(false);
            }
        }
    }
  3. Example execution output in the android studio Logcat console.
    android-async-task-log-output

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.