Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Asynchronous Android Programming - Second Edition

You're reading from  Asynchronous Android Programming - Second Edition

Product type Book
Published in Jul 2016
Publisher Packt
ISBN-13 9781785883248
Pages 394 pages
Edition 2nd Edition
Languages
Author (1):
Steve Liles Steve Liles
Profile icon Steve Liles

Table of Contents (19) Chapters

Asynchronous Android Programming Second Edition
Credits
About the Author
About the Reviewer
www.PacktPub.com
Preface
1. Asynchronous Programming in Android 2. Performing Work with Looper, Handler, and HandlerThread 3. Exploring the AsyncTask 4. Exploring the Loader 5. Interacting with Services 6. Scheduling Work with AlarmManager 7. Exploring the JobScheduler API 8. Interacting with the Network 9. Asynchronous Work on the Native Layer 10. Network Interactions with GCM 11. Exploring Bus-based Communications 12. Asynchronous Programing with RxJava Index

Chapter 3. Exploring the AsyncTask

In Chapter 2, Performing Work with Looper, Handler and HandlerThread, we familiarized ourselves with the most basic asynchronous and concurrency constructs available on the Android platform: Handler and Looper. Those constructs underpin most of the evented and sequential processing used by the main thread to render the UI and to run the Android components life cycle.

In this chapter, we are going to explore android.os.AsyncTask, a higher level construct that provides us with a neat and lean interface to perform background work and publish results back to the main thread without having to manage the thread creation and the handler manipulation.

In this chapter we will cover the following topics:

  • Introducing AsyncTask

  • Declaring AsyncTask types

  • Executing AsyncTasks

  • Providing indeterministic progress feedback

  • Providing deterministic progress feedback

  • Canceling an AsyncTask

  • Handling exceptions

  • Controlling the level of concurrency

  • Common AsyncTask issues

  • Applications of...

Introducing AsyncTask


AsyncTask was introduced on the Android platform with Android Cupcake (API Level 3), with the express purpose of helping developers to avoid blocking the main thread. The Async part of the name of this class comes from the word asynchronous, which literally means that the blocking task is not occurring at the same time we call it.

The AsyncTask encloses the creation of the background thread, the synchronization with the main thread, and the publishing of the progress of the execution in a single construct.

In contrast to the Handler and Looper constructs, the AsyncTask exempts the developer from the management of low level components, thread creation, and synchronization.

AsyncTask is an abstract class, and as such, must be subclassed for use. At the minimum, our subclass must provide an implementation for the abstract doInBackground method, which defines the work that we want to get done off the main thread.

protected Result doInBackground(Params... params)

The doInBackground...

Declaring AsyncTask types


AsyncTask is a generically typed class that exposes three generic type parameters:

abstract class AsyncTask<Params, Progress, Result>

In order to use a generic type, we must provide one type argument per type parameter that was declared for the generic type.

Note

The generic type class provides a way to re-use the same generic algorithms for different input types. A generic type could have one or more type parameters.

When we declare an AsyncTask subclass, we'll specify the types for Params, Progress, and Result; for example, if we want to pass a String parameter to doInBackground, report progress as a Float, and return a Boolean result, we would declare our AsyncTask subclass as follows:

    public class MyTask extends AsyncTask<String, Float, Boolean>

If we don't need to pass any parameters, or don't want to report progress, a good type to use for those parameters is java.lang.Void, which signals our intent clearly, because Void is an uninstantiable class...

Executing AsyncTasks


Having implemented doInBackground and onPostExecute, we want to get our task running. There are two methods we can use for this, each offering different levels of control over the degree of concurrency with which our tasks are executed. Let's look at the simpler of the two methods first:

  public final AsyncTask<Params, Progress, Result> execute(Params...
  params)

The return type is the type of our AsyncTask subclass, which is simply for convenience so that we can use method chaining to instantiate and start a task in a single line and still record a reference to the instance:

   class MyTask implements AsyncTask<String,Void,String>{ ... }
   MyTask task = new MyTask().execute("hello");

The Params... params argument is the same Params type we used in our class declaration, because the values we supply to the execute method are later passed to our doInBackground method as its Params... params arguments. Notice that it is a varargs (variable number of parameters...

Providing indeterministic progress feedback


Having started what we know to be a potentially long-running task, we probably want to let the user know that something is happening. There are a lot of ways of doing this, but a common approach is to present a dialog displaying a relevant message.

A good place to present our dialog is from the onPreExecute() method of AsyncTask which executes on the main thread so it is allowed to interact with the user interface.

The modified DownloadImageTask will need a reference to a Context, so that it can prepare a ProgressDialog, which it will show and dismiss in onPreExecute() and onPostExecute() respectively. As doInBackground() has not changed, it is not shown in the following code, for brevity:

public class DownloadImageTask
  extends AsyncTask<URL, Integer, Bitmap> {
  ...
  private final WeakReference<Context> ctx;
  private ProgressDialog progress;
  ...
  public DownloadImageTask(Context ctx, ImageView imageView) {
    this.imageView =...

Providing deterministic progress feedback


Knowing that something is happening is a great relief to our users, but they might be getting impatient and wondering how much longer they need to wait. Let's show them how we're getting on by adding a progress bar to our dialog.

Remember that we aren't allowed to update the user interface directly from doInBackground(), because we aren't on the main thread. How, then, can we tell the main thread to make these updates for us?

AsyncTask comes with a handy callback method for this, whose signature we saw at the beginning of the chapter:

protected void onProgressUpdate(Progress... values)

We can override onProgressUpdate() to update the user interface from the main thread, but when does it get called and where does it get its Progress... values from? The glue between doInBackground() and onProgressUpdate() is another of AsyncTask's methods:

   protected final void publishProgress(Progress... values)

To update the user interface with our progress, we simply...

Canceling an AsyncTask


Another nice usability touch we can provide for our users is the ability to cancel a task before it completes—for example, if after starting the execution, the user is no longer interested in the operation result. AsyncTask provides support for cancellation with the cancel method.

public final boolean cancel(boolean mayInterruptIfRunning)

The mayInterruptIfRunning parameter allows us to specify whether an AsyncTask thread that is in an interruptible state, may actually be interrupted—for example, if our doInBackground code is performing a blocking interruptible function, such as Object.wait(). When we set the mayInterruptIfRunning as false, the AsyncTask won't interrupt the current interruptible blocking operation and the AsyncTask background processing will only finish once the blocking operation terminates.

Note

In well behaved interruptible blocking functions, such as Thread.sleep(), Thread.join(), or Object.wait(), the execution is stopped immediately when the thread...

Handling exceptions


The callback methods defined by AsyncTask dictate that we cannot throw checked exceptions, so we must wrap any code that throws checked exceptions with try/catch blocks. Unchecked exceptions that propagate out of AsyncTask's methods will crash our application, so we must test carefully and handle these if necessary.

For the callback methods that run on the main thread—onPreExecute(), onProgressUpdate(), onPostExecute(), and onCancelled()—we can catch exceptions in the method and directly update the user interface to alert the user.

Of course, exceptions are likely to arise in our doInBackground() method too, as this is where the bulk of the work of AsyncTask is done, but unfortunately, we can't update the user interface from doInBackground(). A simple solution is to have doInBackground() return an object that may contain either the result or an exception. First we are going to create a generic class for storing the result of an operation and a member to store an exception...

Controlling the level of concurrency


So far, we've carefully avoided being too specific about what exactly happens when we invoke the AsyncTask execute method. We know that doInBackground() will execute off the main thread, but what exactly does that mean?

The original goal of AsyncTask was created to help developers avoid blocking the main thread. In its initial form at API level 3, AsyncTasks were queued and executed serially (that is, one after the other) on a single background thread, guaranteeing that they would complete in the order they were started.

This changed in API level 4 to use a pool of up to 128 threads to execute multiple AsyncTasks concurrently with each other—a level of concurrency of up to 128. At first glance, this seems like a good thing, since a common use case for AsyncTask is to perform blocking I/O, where the thread spends much of its time idly waiting for data.

However, as we saw in Chapter 1, Building Responsive Android Applications, there are many issues that commonly...

Common AsyncTask issues


As with any powerful programming abstraction, AsyncTask is not entirely free from issues and compromises. In the next sections we are going to list some of the pitfalls that we could face when we want to make use of this construct in our applications.

Fragmentation issues

In the Controlling the level of concurrency section, we saw how AsyncTask has evolved with new releases of the Android platform, resulting in behavior that varies with the platform of the device running the task, which is a part of the wider issue of fragmentation.

The simple fact is that if we target a broad range of API levels, the execution characteristics of our AsyncTasks—and therefore, the behavior of our apps— can vary considerably on different devices. So what can we do to reduce the likelihood of encountering AsyncTask issues due to fragmentation?

The most obvious approach is to deliberately target devices running at least Honeycomb, by setting a minSdkVersion of 11 in the Android Manifest file...

Applications of AsyncTask


Now that we have seen how to use AsyncTask, we might ask ourselves when we should use it.

Good candidate applications for AsyncTask tend to be relatively short-lived operations (at most, for a second or two), which pertain directly to a specific Fragment or Activity and need to update its user interface.

AsyncTask is ideal for running short, CPU-intensive tasks, such as number crunching or searching for words in large text strings, moving them off the main thread so that it can remain responsive to input and maintain high frame rates.

Blocking I/O operations such as reading and writing text files, or loading images from local files with BitmapFactory are also good use cases for AsyncTask.

Of course, there are use cases for which AsyncTask is not ideally suited. For anything that requires more than a second or two, we should weigh the cost of performing this operation repeatedly if the user rotates the device, or switches between apps or activities, or whatever else...

Summary


In this chapter, we've taken a detailed look at AsyncTask and how to use it to write responsive applications that perform operations without blocking the main thread.

We saw how to keep users informed of the progress, and even allow them to cancel operations early. We also learned how to deal with issues that can arise when the Activity lifecycle conspires against our background tasks.

Finally, we considered when to use AsyncTask, and when it might not be appropriate.

In the next chapter we'll learn about Loader—a construct designed to streamline the asynchronous loading of data on the Android platform.

lock icon The rest of the chapter is locked
You have been reading a chapter from
Asynchronous Android Programming - Second Edition
Published in: Jul 2016 Publisher: Packt ISBN-13: 9781785883248
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at AU $19.99/month. Cancel anytime}