Book Image

Asynchronous Android Programming - Second Edition

By : Steve Liles
Book Image

Asynchronous Android Programming - Second Edition

By: Steve Liles

Overview of this book

Asynchronous programming has acquired immense importance in Android programming, especially when we want to make use of the number of independent processing units (cores) available on the most recent Android devices. With this guide in your hands you’ll be able to bring the power of Asynchronous programming to your own projects, and make your Android apps more powerful than ever before! To start with, we will discuss the details of the Android Process model and the Java Low Level Concurrent Framework, delivered by Android SDK. We will also guide you through the high-level Android-specific constructs available on the SDK: Handler, AsyncTask, and Loader. Next, we will discuss the creation of IntentServices, Bound Services and External Services, which can run in the background even when the user is not interacting with it. You will also discover AlarmManager and JobScheduler APIs, which are used to schedule and defer work without sacrificing the battery life. In a more advanced phase, you will create background tasks that are able to execute CPU-intensive tasks in a native code-making use of the Android NDK. You will be then guided through the process of interacting with remote services asynchronously using the HTTP protocol or Google GCM Platform. Using the EventBus library, we will also show how to use the Publish-Subscribe software pattern to simplify communication between the different Android application components by decoupling the event producer from event consumer. Finally, we will introduce RxJava, a popular asynchronous Java framework used to compose work in a concise and reactive way. Asynchronous Android will help you to build well-behaved applications with smooth responsive user interfaces that delight the users with speedy results and data that’s always fresh.
Table of Contents (19 chapters)
Asynchronous Android Programming Second Edition
Credits
About the Author
About the Reviewer
www.PacktPub.com
Preface
2
Performing Work with Looper, Handler, and HandlerThread
Index

Android thread model


Within an Android process, there may be many threads of execution. Each thread is a separate sequential flow of control within the overall program—it executes its instructions in order, one after the other, and they also share allocated slices of CPU time managed by the operating system task scheduler.

While the application process is started by the system and prevented from directly interfering with data in the memory address space of other processes, the threads may be started by an application code and can communicate and share data with other threads within the same process. Apart from the shared data that all the threads share in the same process, a thread can use its own memory cache to store its data in its own memory space.

The main thread

When the application process starts, apart from DVM housekeeping threads, the system creates a thread of execution called main. This thread, as the name explains, plays a crucial role in the application lifetime as it is the thread that interacts with the Android UI components, updating the state and their look on the device screen.

Moreover, by default, all the Android application components (Activity, Service, ContentProvider, and BroadcastsReceiver) are also executed over the main thread line of execution. The following image shows the lists of threads running inside an application process with the main thread at the top of the list with a unique thread ID (TID) assigned by the system:

The main thread, also known as UI Thread, is also the thread where your UI event handling occurs, so to keep your application as responsible as possible, you should:

  • Avoid any kind of long execution task, such as input/output (I/O) that could block the processing for an indefinite amount of time

  • Avoid CPU-intensive tasks that could make this thread occupied for a long time

The following diagram displays the main interactions and components involved in the Looper line of execution thread:

The UI/Main thread, which has a Looper facility attached to it, holds a queue of messages (MessageQueue) with some unit of work to be executed sequentially.

When a message is ready to be processed on the queue, the Looper Thread pops the message from the queue and forwards it synchronously to the target handler specified on the message.

When the target Handler finishes its work with the current message, the Looper thread will be ready to process the next message available on the queue. Hence, if the Handler spent a noticeable amount of time processing the message, it will prevent Looper from processing other pending messages.

For example, when we write the code in an onCreate() method in the Activity class, it will be executed on the main thread. Likewise, when we attach listeners to user-interface components to handle taps and other user-input gestures, the listener callback executes on the main thread.

For apps that do little I/O or processing, such as applications that don't do complex math calculations, don't use the network to implement features, or don't use filesystem resources, this single thread model is fine. However, if we need to perform CPU-intensive calculations, read or write files from permanent storage, or talk to a web service, any further events that arrive while we're doing this work will be blocked until we're finished.

Note

Since the Android 5.0 (Lollipop), a new important thread named RenderThread was introduced to keep the UI animations smooth even when the main thread is occupied doing stuff.

The Application Not Responding (ANR) dialog

As you can imagine, if the main thread is busy with a heavy calculation or reading data from a network socket, it cannot immediately respond to user input such as a tap or swipe.

An application that doesn't respond quickly to user interaction will feel unresponsive—anything more than a couple of hundred milliseconds delay is noticeable. This is such a pernicious problem that the Android platform protects users from applications that do too much on the main thread.

Note

If an app does not respond to user input within five seconds, the user will see the Application Not Responding (ANR) dialog and will be offered the option to quit the application.

The following screenshot shows a typical Android ANR dialog:

Android works hard to synchronize the user interface redraws with the hardware-refresh rate. This means that it aims to redraw at the rate of 60 frames per second—that's just 16.67 ms per frame. If we do work on the main thread that takes anywhere near 16 ms, we risk affecting the frame rate, resulting in jank—stuttering animations, jerky scrolling, and so on.

Ideally, of course, we don't want to drop a single frame. Jank, unresponsiveness, and especially the ANR, offer a very poor user experience, which translates into bad reviews and unpopular applications. A rule to live by when building Android applications is: do not block the main thread!

Note

Android provides a helpful strict mode setting in Developer Options on each device, which will flash on the screen when applications perform long-running operations on the main thread.

Further protection was added to the platform in Honeycomb (API level 11) with the introduction of a new Exception class, NetworkOnMainThreadException, a subclass of RuntimeException that is thrown if the system detects network activity initiated on the main thread.

Maintaining responsiveness

Ideally then, we may want to offload any long-running operations from the main thread so that they can be handled in the background by another thread, and the main thread can continue to process user-interface updates smoothly and respond in a timely fashion to user interactions.

The typical time-consuming tasks that should be handled on a background thread include the following:

  • Network communications

  • Input and output file operations on the local filesystem

  • Image and video processing

  • Complex math calculations

  • Text processing

  • Data encoding and decoding

For this to be useful, we must be able to coordinate the work and safely pass data between cooperating threads—especially between background threads and the main thread, and it is exactly to solve this problem that asynchronous programming is used.

Let's get started with the synchronous versus asynchronous diagram:

The preceding example graphically shows the main differences between the two models of processing. On the left-hand side, the data download task occurs on the main thread, keeping the thread busy until the download data is finished. So if the user interacts with the UI and generates an event such as a touch event, the application will suffer a lag or will become unresponsive if the download task takes a substantial amount of time to finish.

On the right-hand side, the asynchronous model will hand over the download data task to another background thread, keeping the main thread available to process any event coming from the UI interaction. When the downloaded data is available, the background task could post the result to the main thread if the data handling needs to update any UI state.

When we use an asynchronous model to program our application, the Android OS will also take advantage of additional CPU cores available in the most recent devices to execute multiple background threads at the same time and increase the application's power efficiency.

Note

This simultaneous execution of separate code paths that potentially interact with each other is known as concurrency.

The simultaneous execution of subunits of work in parallel to complete one unit of work is known as parallelism.