The following is the first few sections of a chapter from The Busy Coder's Guide to Android Development, plus headings for the remaining major sections, to give you an idea about the content of the chapter.
Users like snappy applications. Users do not like applications that feel sluggish.
The way to help your application feel snappy is to use the standard threading capabilities built into Android. This chapter will go through the issues involved with thread management in Android and will walk you through some of the options for keeping the user interface crisp and responsive.
When you call
setText() on a
TextView, you probably think that the screen
is updated with the text you supply, right then and there.
You would be mistaken.
Rather, everything that modifies the widget-based UI goes through a message
queue. Calls to
setText() do not update the screen — they just place a
message on a queue telling the operating system to update the screen. The
operating system pops these messages off of this queue and does what the
The queue is processed by one thread, variously called the “main application thread” and the “UI thread”. So long as that thread can keep processing messages, the screen will update, user input will be handled, and so on.
However, the main application thread is also used for nearly all callbacks into
your activity. Your
onListItemClick(), and similar
methods are all called on the main application thread. While your code is
executing in these methods, Android is not processing messages on the queue,
and so the screen does not update, user input is not handled, and so on.
This, of course, is bad. So bad, that if you take more than a few seconds to do work on the main application thread, Android may display the dreaded “Application Not Responding” dialog (ANR for short), and your activity may be killed off.
Nowadays, though, the bigger concern is jank.
“Jank”, as used in Android, refers to sluggish UI updates, particularly when
something is animating. For example, you may have encountered some apps that
when you scroll a
ListView in the app, the
ListView does not scroll smoothly.
Rather, it scrolls jerkily, interleaving periods of rapid movement with periods
where the animation is frozen. Most of the time, this is caused by the
app’s author doing too much work on the main application thread.
Android 4.1 introduced “Project Butter”, which, among other things, established a baseline for “doing too much work on the main application thread”. We will “drop frames” if we take more than ~16ms per frame (60 frames per second), and dropped frames are the source of jank. Since we may be called many times during a frame, each of our callbacks needs to be very cheap, ideally below 1ms. We will get much more into the issue of jank later in the book, but it is important to understand now that any significant delay in the execution of our code on the main application thread can have visible effects to the user.
Hence, you want to make sure that all of your work on the main application thread happens quickly. This means that anything slow should be done in a background thread, so as not to tie up the main application thread. This includes things like:
Fortunately, Android supports threads using the standard
Thread class from
Java, plus all of the wrappers and control structures you would expect, such as
java.util.concurrent class package.
However, there is one big limitation: you cannot modify the UI from a
background thread. You can only modify the UI from the main application thread.
If you call
setText() on a
TextView from a background thread, your application
will crash, with an exception indicating that you are trying to modify the UI
from a “non-UI thread” (i.e., a thread other than the main application thread).
This is a pain.
Hence, you need to get long-running work moved into background threads, but those threads need to do something to arrange to update the UI using the main application thread.
There are various facilities in Android for helping with this.
Some are high-level frameworks for addressing this issue for major functional
areas. One example of this is the
Loader framework for retrieving
information from databases, and we will examine this in a later chapter.
Sometimes, there are asynchronous options built into other Android operations.
For example, when we discuss
SharedPreferences in a later chapter, we will
see that we can persist changes to those preferences synchronously or
And, there are a handful of low-level solutions for solving this problem, ones that you can apply for your own custom business logic.
The preview of this section apparently resembled a Pokémon.
The preview of this section is presently indisposed.
The preview of this section was stepped on by Godzilla.
The preview of this section took that left turn at Albuquerque.
The preview of this section is in an invisible, microscopic font.