Chapter 26 Loopers, Handlers, and HandlerThread
Downloading Lots of Small Things
Currently, PhotoGallery’s networking works like this: PhotoGalleryFragment executes an AsyncTask
that retrieves the JSON from Flickr on a background thread and parses the JSON into an array of
GalleryItems. Each GalleryItem now has a URL where a thumbnail-size photo lives.
The next step is to go and get those thumbnails. You might think that this additional networking code
could simply be added to FetchItemsTask’s doInBackground(...) method. Your GalleryItem array has
100 URLs to download from. You would download the images one after another until you had all 100.
When onPostExecute(...) executed, they would be displayed en masse in the RecyclerView.
However, downloading the thumbnails all at once causes two problems. The first is that it could take
a while, and the UI would not be updated until the downloading was complete. On a slow connection,
users would be staring at a wall of Bills for a long time.
The second problem is the cost of having to store the entire set of images. One hundred thumbnails will
fit into memory easily. But what if it were 1,000? What if you wanted to implement infinite scrolling?
Eventually, you would run out of space.
Given these problems, real-world apps often download images only when they need to be displayed
onscreen. Downloading on demand puts the responsibility on the RecyclerView and its adapter. The
adapter triggers the image downloading as part of its onBindViewHolder(...) implementation.
AsyncTask is the easiest way to get a background thread, but it is ill-suited for repetitive and long-
running work. (You can read why in the section called For the More Curious: AsyncTasks vs Threads at
the end of this chapter.)
Instead of using an AsyncTask, you are going to create a dedicated background thread. This is the most
common way to implement downloading on an as-needed basis.
Communicating with the Main Thread
Your dedicated thread will download photos, but how will it work with the RecyclerView’s adapter to
display them when it cannot directly access the main thread?
Think back to the shoe store with two Flashes. Background Flash has wrapped up his phone call to
the distributor. He needs to tell Main Flash that the shoes are back in stock. If Main Flash is busy,
Background Flash cannot do this right away. He would have to wait by the register to catch Main Flash
at a spare moment. This would work, but it would not be very efficient.
The better solution is to give each Flash an inbox. Background Flash writes a message about the shoes
being in stock and puts it on top of Main Flash’s inbox. Main Flash does the same thing when he wants
to tell Background Flash that the stock of shoes has run out.
The inbox idea turns out to be really handy. The Flash may have something that needs to be done soon,
but not right at the moment. In that case, he can put a message in his own inbox and then handle it
when he has time.