Background Processing

In Android applications, there’s always at least one main thread that executes the most important tasks, handling user interaction, drawing pixels on the screen, and launching activities. This thread is called the UI Thread, or Main Thread. Because it’s handling the most crucial parts of an app, you never want to block the UI thread when you’re coding activities—it could cause your app to lag, skip, or crash. The more complicated the tasks get in an app, the more opportunities to block the main thread. If an activity does not react within 5 seconds to user input, you will get one of these

application not responding dialog - AsyncTask Example

Application not Responding dialog

Performing slow and long running task on the main thread is bad because

  • It makes an app less useful
  • It ties up resources
  • It wastes time
  • It freezes the User Interface
  • It breaks design principles
  • It’s ultimately leads to Poor User Experience, rapid Uninstalls and lots of 1 star Ratings

To provide a great user experience it’s critical to design responsiveness into your application so the system never displays an ANR dialog to the user.

Potentially slow operations are for example network, file and database access and complex calculations. One way to run this lengthy/slow tasks asynchronously is by using AsyncTask.

Async Task

Android AsyncTask is a generic and an abstract class that encloses the functionality of Thread and Handler class provided by Android which allow us to run a task in the background thread while publishing results to the UI thread, thus making the application more responsive (yay!). It basically combines the functionality of both the classes that is apt for the context of android.

To use AsyncTask you must subclass it (you cannot make objects from Abstract classes). AsyncTask allows to run instructions in the background and to synchronize again with the main thread. It can also report progress of the running tasks to the main thread.

[box type=”note” align=”” class=”” width=””]
Other ways you might achieve threading (running tasks in background) your application is to instead create your own Thread or HandlerThread class or use a Service and/or Loader and/or Executor. Note: These approaches are a little more complicated than AsyncTask[/box]

The three generic types used in an android AsyncTask <Params, Progress, Result> class are :

  • Params : The type of parameter to be sent to doInBackground()
  • Progress : The type of the progress units to be published (to main thread) during the background computation.
  • Result : The desired type of the result of the background computation

[box type=”note” align=”” class=”” width=””]
A Generic class takes parameterized types in it’s constructor, each of these generic parameters is defined as a Java Variable argument with a three dot ( . . . ) which means it technically passes in an array

What is the meaning Params… in android?
It is a Java concept know as var args. It is sugar syntax to pass array of certain type in as method argument.
So when you say

Long doInBackground (String... strings){
  String[] vals = strings;
}

and you can access values from that array.

As far as AsyncTask’s methods are concerned, you can change argument type from Params to the type you need. Params is just a template which you need to change during implementation.
[/box]

The basic methods used in an android AsyncTask class are:

  • onPreExecute() : This method contains the code which is executed before the background processing starts. It is generally used to create dialog box or progress bar and carry out initialization(s).
  • doInBackground() : This method contains the code which needs to be executed in the background and it is mandatory to be over-written. In this method we can send updates (about progress made in long running task), countless times to the UI (or main) thread by using publishProgress(Params...progress) method.
  • onProgressUpdate() : This method receives progress updates from doInBackground() method with Progress generic parameter. With this you can update the UI thread. For instance, it can be used to animate a progress bar or in our case, show logs in a text field.
  • onPostExecute() : This method is called after doInBackground() method is done with background computation. The Result parameter from doInBackground() is passed to this method

An AsyncTask is started via the execute() method.

This execute() method calls the doInBackground() method.

The doInBackground() method contains the coding instruction which should be performed in a background thread. This method runs automatically in a separate Thread.

Params is passed into doInBackground() method as input.

Once doInBackground() is done, it calls onPostExecute() passing Result value to it. The onPostExecute()  method synchronizes itself again with the user interface thread and allows it to be updated.

Progress is used for progress information and Result is returned from doInBackground() method. This parameter is passed to onPostExecute() as a parameter.

For example AsyncTask<String, Integer, Bitmap> means that the task requires a string input to execute, records its progress in integer number and returns a Bitmap after the task is complete.

AsyncTask diagram

AsyncTask diagram

[box type=”warning” align=”” class=”” width=””]Before you get too excited about using AsyncTask in all of your applications, please read its advantages, disadvantages and conclusion at the end of this page.[/box]

When to use AsyncTask

  • Short or Interruptible tasks.
  • Small task having to communicate with main thread
  • Low-priority tasks that can be left unfinished.
  • Disk-bound tasks that might take more than a few milliseconds
  • For tasks in parallel use multiple instances OR Executor

Enough talk let’s code!

We are going to build an app that adds up numbers between one to one million, that is 1+2 + 3+ … +2345 +…+23456 …. +1000000.

Most android devices have incredibly fast CPUs, thus, such calculations will be fast. in order to demonstrate how to use onProgressUpdate(), we would slow down the process. To achieve this, we would do the summation repeatedly, a hundred,100 times, that is after adding 1 to 1 million the first time we will go over it again, add from 1 to 1 million until a hundred loop completes. The result of our summation in each loop will be constant and equal.  That is, the summation of 1 to 1 million in loop 1 will be equal to  the summation of 1 to 1 million in loop 2 and so on –  equal and constant.

[box type=”download” align=”aligncenter” class=”” width=””]Download source code from Github[/box]

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private TextView progressTxtView, finalResultTxtView;
    private AsyncTaskSubClass asyncExample;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        progressTxtView = (TextView) findViewById(R.id.progress_text_view);
        finalResultTxtView = (TextView) findViewById(R.id.result_text_view);
    }

    public void startComputation(View view) {
            asyncExample = new AsyncTaskSubClass();
            asyncExample.execute("1,000,000"); // ten Million
            Toast.makeText(MainActivity.this, "Computation Started", Toast.LENGTH_SHORT).show();
    }

    public void cancelComputation(View view) {
        if (asyncExample != null){
            //Calling this method guarantees that onPostExecute(Long result) is never invoked
            asyncExample.cancel(true);
            asyncExample = null;
            Toast.makeText(this, "Async Task Stopped!", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "You have no running task!", Toast.LENGTH_SHORT).show();
        }
    }

    class AsyncTaskSubClass extends AsyncTask<String, Integer, Long> {
        private String firstString;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            // initializing our textviews before doInBackground
            progressTxtView.setText("");
            finalResultTxtView.setText("Result would be displayed Here");
        }

        @Override
        protected Long doInBackground(String... strings) {
            firstString = strings[0]; // first String
            int number = 1 + Integer.parseInt(firstString.replace(",", ""));
            long result = 0;
            // we are going to do a long computation
            for (int i = 1; i < 101; i++) { // from 1 to 100

                if (isCancelled())  {
                    return result;
                }
                result = 0;
                for (int j = 1; j < number; j++) {
                    result = result + j;
                }
                Log.d("AsyncTaskSubClass", "doInBackground: Result"+i+" = " +result);
                publishProgress(i);
            }
            return result;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            progressTxtView.setText(values[0] + " %");
        }

        @Override
        protected void onPostExecute(Long longResult) {
            super.onPostExecute(longResult);
            asyncExample = null;
            String string = "The summation of Numbers between 1 to " + firstString + " is \n=" + longResult;
            finalResultTxtView.setText(string);
            Toast.makeText(MainActivity.this, "Computation Completed!", Toast.LENGTH_SHORT).show();
        }
    }
}

activity_main.xml

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

    <!--A button to execute our Async Task-->
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Computation"
        android:onClick="startComputation"
        android:layout_marginBottom="16dp"
        android:id="@+id/start_button"/>

    <!--This TextView Will Show Progress of Calculation-->
    <TextView
        android:id="@+id/progress_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="16dp"
        android:layout_marginBottom="8dp"
        android:background="@android:color/holo_orange_light"
        android:textColor="@android:color/holo_red_dark"
        android:textSize="22sp"
        tools:text="22 %"
        android:textStyle="bold"/>

    <!--This TextView Will Show Final Result-->
    <TextView
        android:id="@+id/result_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:background="@color/colorAccent"
        android:textColor="@android:color/white"
        android:textSize="22sp"
        android:text="Result would be displayed Here"/>

    <!--Button to help us cancel -->
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Cancel Computation"
        android:layout_marginTop="16dp"
        android:onClick="cancelComputation"
        android:id="@+id/cancel_button"/>
</LinearLayout>

we used publishProgress(Integer…params) within doInBackground() to send Integer params to be used to update the UI.

How do we Cancel AsyncTask?

by calling  cancel(boolean mayInterruptIfRunning) on the object of AsyncTask sub class as shown on line 22 in MainActivity. The cancel method receives  a Boolean parameter (may-Interrupt-If-Running) and all it does is send an interrupt()to the running Thread.

Advantages of AsyncTask

  1. it’s simple, quick and easy to use in order to achieve threading and simultaneously update the UI without having to manipulate threads and/or handlers.

Disadvantages of AsyncTask

  1. Configuration changes and  NullPointerExceptions: when a configuration change occurs, such as screen rotation, the activity is recreated, when this happens, your AsyncTask’s reference to the new Activity is invalid, although, your AsyncTask will continue to run (in the background), and  onPostExecute() will have no effect on the new Activity. If in the new Activity, you fire another AsyncTask, you’ll have to wait for the ‘invalid’ AsyncTask to finish it’s work. NullPointerExceptions can occur if some views or variable referenced by the ‘invalid’ AsyncTask are  initialized to be null in the new Activity.
  2. One at a Time: multiple executed AsyncTasks will be added to a queue and executed one after the other – in a background thread.
  3. Limited Number of concurrent task: you can have a maximum of 128 AsyncTasks, although developers rarely reach this limit.
  4. Cancelling AsyncTasks: i showed you how to cancel AsyncTask above, right? scratch that. calling the AsyncTask.cancel() does not kill the background thread, all it does is set the AsyncTask to a “cancelled” state Boolean cancelled = true.  It’s up to you to check whether the AsyncTask has been cancelled (AsyncTask.isCancelled()) (as shown on line 49 – 51 in MainActivity.java) so that you can halt your operation. Calling AsyncTask.cancel() alone (without utilizing isCancelled()) will only stop onProgressUpdate() but backgroud process will continue to work.
    //Our Object
    AsyncTaskSubClass asyncExample = new AsyncTaskSubClass();
    
    // To Cancel
    asyncExample.cancel(true); // sends an interrupt() to the running Thread
    
    //What our doInBackground method will look like
    @Override
    protected Long doInBackground(String... strings) {
        long result = 0;
        ...
    // Check if the state has changed to cance, if yes, halt the thread!. If no, continue threading!
        if (isCancelled())  { 
          return result;
        }
        ...
        return result;
    }
  5. Must be created and executed from the Main thread
  6. Incompatible with Fragments. AsyncTask can be used with a Fragment but that comes at a price, most times it’s not worth it.

You may read: Simple Solutions to Pitfalls of Async Task.

Alternatives to AsyncTask

  • Android Libraries – Android-Arsenal
  • Android Threading Constructs – AsyncTaskLoader, Services, Executors etc

Conclusion

AsyncTask is a great tool to access and use a background thread without having to deal with complex Handler and/or Thread interactions (locking) while simultaneous Updating the UI (Awesome Stuff!!) but It is much better to use AsyncTaskLoader for task you’ll commonly use AsyncTask for. One main advantage of AsyncTaskLoader is that, it is lifecycle aware such that when android configuration changes – such as screen rotation – it will retain references to the needed variables or views used by the background thread. Always use AsyncTaskLoader in place of AsyncTask!

[box type=”shadow” align=”” class=”” width=””]

References

[/box]

Leave a comment