ThumbnailDownloader Implementation


#1

Hello everyone,

I have two questions about the ThumbnailDownloader Implementation in the book:
(1) The ThumbnailDownloader class has extended from handlerThread, could anyone explain why we do not need to override the run() method?
(2) Could anyone explain why can we call the ThumbnailDownloader thread’s method from main thread()?

Thank you so much.

Best regards,
Jinwei


#2

1- HandlerThread overrides run() itself to setup Looper. Once the Looper is run, you can use a Handler to execute code on the thread instead of using a run() implementation like you would with a normal thread.

2- The queueThumbnail method is ThumbnailDownloader’s public interface. It’s used to give ThumbnailDownloader work to do.

Let me know if you need any more clarification.


#3

In main thread’s onCreate() method, you use mThumbnailThread.start() to start the mThumbnailThread thread.

and the mThumbnailThread has overriden the thread’s run() method

public class HandlerThread extends Thread {
    ...
    @Override
    public void run() {
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
    }
    ....
}

in this run() method
1.Looper.prepare(); // use a threadLocal instance to connect the mThumbnailThread and its looper

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    sThreadLocal.set(new Looper(quitAllowed));

2.onLooperPrepared(); // define an mHandler attached to the mThumbnailThread and the handlerMessage() method to handle the download task in the mThumbnailThread, we override this method

protected void onLooperPrepared() {
        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == MESSAGE_DOWNLOAD) {
                    Token token = (Token) msg.obj;
                    Log.i(TAG, "Got a request for url: " + requestMap.get(token));
                    handleRequest(token);
                }
            }
        };
    }

3.Looper.loop(); // if the message queue is blank, the looper will block, else the looper will poll the msg from the message queue and use the msg.target(it’s just the mHandler) to handle it

for (;;) {
            Message msg = queue.next(); // might block
            msg.target.dispatchMessage(msg);
}

in main UI thread, GalleryItemAdapter’s getView() method will use mThumbnailThread.queueThumbnail(imageView, item.getUrl()) to push the msg into message queue.

public void queueThumbnail(Token token, String url) {
        Log.i(TAG, "Got an URL: " + url);

        requestMap.put(token, url);

        mHandler.obtainMessage(MESSAGE_DOWNLOAD, token).sendToTarget();
    }

mHandler.obtainMessage() will create a msg, and msg.sendToTarget() will push the msg into the tail of the message queue, because mHandler is created in the mThumbnailThread, the download task will run() on mThumbnailThread using the mHandler.handleMessage()