Assembling a Background Thread

Create a new class called ThumbnailDownloader that extends HandlerThread. Then give it a constructor, a stub implementation of a method called queueThumbnail(), and an override of the quit() method that signals when your thread has quit. (Toward the end of the chapter, you will need this bit of information.)

Listing 26.4  Initial thread code (ThumbnailDownloader.java)

public class ThumbnailDownloader<T> extends HandlerThread {
    private static final String TAG = "ThumbnailDownloader";

    private boolean mHasQuit = false;

    public ThumbnailDownloader() {
        super(TAG);
    }

    @Override
    public boolean quit() {
        mHasQuit = true;
        return super.quit();
    }

    public void queueThumbnail(T target, String url) {
        Log.i(TAG, "Got a URL: " + url);
    }
}

Notice that you gave the class a single generic argument, <T>. Your ThumbnailDownloader’s user, PhotoGalleryFragment in this case, will need to use some object to identify each download and to determine which UI element to update with the image once it is downloaded. Rather than locking the user into a specific type of object as the identifier, using a generic makes the implementation more flexible.

The queueThumbnail() method expects an object of type T to use as the identifier for the download and a String containing the URL to download. This is the method you will have PhotoAdapter call in its onBindViewHolder(…) implementation.

Open PhotoGalleryFragment.java. Give PhotoGalleryFragment a ThumbnailDownloader member variable. In onCreate(…), create the thread and start it. Override onDestroy() to quit the thread.

Listing 26.5  Creating ThumbnailDownloader (PhotoGalleryFragment.java)

public class PhotoGalleryFragment extends Fragment {

    private static final String TAG = "PhotoGalleryFragment";

    private RecyclerView mPhotoRecyclerView;
    private List<GalleryItem> mItems = new ArrayList<>();
    private ThumbnailDownloader<PhotoHolder> mThumbnailDownloader;
    ...
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        new FetchItemsTask().execute();

        mThumbnailDownloader = new ThumbnailDownloader<>();
        mThumbnailDownloader.start();
        mThumbnailDownloader.getLooper();
        Log.i(TAG, "Background thread started");
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        ...
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mThumbnailDownloader.quit();
        Log.i(TAG, "Background thread destroyed");
    }
    ...
}

You can specify any type for ThumbnailDownloader’s generic argument. However, recall that this argument specifies the type of the object that will be used as the identifier for your download. In this case, the PhotoHolder makes for a convenient identifier as it is also the target where the downloaded images will eventually go.

A couple of safety notes. One: Notice that you call getLooper() after calling start() on your ThumbnailDownloader (you will learn more about the Looper in a moment). This is a way to ensure that the thread’s guts are ready before proceeding, to obviate a potential (though rarely occurring) race condition. Until you call getLooper(), there is no guarantee that onLooperPrepared() has been called, so there is a possibility that calls to queueThumbnail(…) will fail due to a null Handler.

Safety note number two: You call quit() to terminate the thread inside onDestroy(). This is critical. If you do not quit your HandlerThreads, they will never die. Like zombies. Or rock and roll.

Finally, within PhotoAdapter.onBindViewHolder(…), call the thread’s queueThumbnail() method and pass in the target PhotoHolder where the image will ultimately be placed and the GalleryItem’s URL to download from.

Listing 26.6  Hooking up ThumbnailDownloader (PhotoGalleryFragment.java)

public class PhotoGalleryFragment extends Fragment {
  ...
  private class PhotoAdapter extends RecyclerView.Adapter<PhotoHolder> {
    ...
    @Override
    public void onBindViewHolder(PhotoHolder photoHolder, int position) {
        GalleryItem galleryItem = mGalleryItems.get(position);
        Drawable placeholder = getResources().getDrawable(R.drawable.bill_up_close);
        photoHolder.bindDrawable(placeholder);
        mThumbnailDownloader.queueThumbnail(photoHolder, galleryItem.getUrl());
    }
    ...
  }
    ...
}

Run PhotoGallery and check out Logcat. When you scroll around the RecyclerView, you should see lines in Logcat signaling that ThumbnailDownloader is getting each one of your download requests.

Now that you have a HandlerThread up and running, the next step is to create a message with the information passed in to queueThumbnail(), and then put that message on the ThumbnailDownloader’s message queue.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
44.222.249.19