Handlers and Loopers

Android defines two classes in the android.os package that will often be the cornerstones of the interthread communication in your multithreaded applications:

  • Handler
  • Looper

While creating an AsyncTask object hides the Handler and Looper details from you, in some cases you need to use handlers and loopers explicitly, for example when you need to post a Runnable to a thread other than the main thread.

Handlers

Listing 5–2 gave you a glimpse of how the Handler and Looper work together: you use a Handler object to post a Runnable in a Looper's message queue. Your application's main thread already has a message queue, so you don't have to create one explicitly. However, the threads you create do not come automatically with a message queue and message loop, so you would have to create one yourself if needed. Listing 5–7 shows how you can create a thread with a Looper.

Listing 5–7. Thread Class With Message Queue

public classMyThreadextendsThread{
    private static final String TAG = “MyThread”;
    privateHandler mHandler;

    public MyThread(String name) {
        super(name);
    }

    public Handler getHandler() {
        return mHandler;
    }

    @Override

    publicvoid run(){
        Looper.prepare(); // binds a looper to this thread

        mHandler =newHandler(){
            @Override
            publicvoid handleMessage(Message msg){
                switch (msg.what) {
                    // process messages here
                }
            }
        };
        // the handler is bound to this thread's looper

        Looper.loop(); // don't forget to call loop() to start the message loop

        // loop() won't return until the loop is stopped (e.g., when Looper.quit() is
called)
    }
}

NOTE: The handler object is created in the run() method as it needs to be bound to a specific looper, which is also created in run() when Looper.prepare() is called. Consequently, calling getHandler() before the thread is spawned will return null.

Once the thread is running, you can post Runnable objects or send messages to its message queue, as shown in Listing 5–8.

Listing 5–8. Posting Runnables and Sending Messages

    MyThread thread = new MyThread(“looper thread”);
    thread.start();

    // later...
    Handler handler = thread.getHandler();
    // careful: this could return null if the handler is not initialized yet!

    // to post a runnable
    handler.post(new Runnable() {
        public void run() {
            Log.i(TAG, "Where am I? " + Thread.currentThread().getName());
        }
    });

    // to send a message
    int what = 0; // define your own values
    int arg1 = 1;
    int arg2 = 2;
    Message msg = Message.obtain(handler, what, arg1, arg2);
    handler.sendMessage(msg);

    // another message...
    what = 1;
    msg = Message.obtain(handler, what, new Long(Thread.currentThread().getId()));
    handler.sendMessageAtFrontOfQueue(msg);

TIP: Use one of the Message.obtain() or Handler.obtainMessage() APIs to get a Message object, as they return a Message object from the global message pool, which is more efficient than allocating a new instance every single time a message is needed. These APIs also make it simpler to set the various fields of the message.

Loopers

Android provides an easier way to work with looper threads with the HandlerThread class, which also makes it easier to avoid the potential race condition mentioned in Listing 5–8, where getHandler() may still return null even after the thread has been started. Listing 5–9 shows how to use the HandlerThread class.

Listing 5–9. Using the HandlerThread Class

public class MyHandlerThread extends HandlerThread {
    private static final String TAG = "MyHandlerThread";
    private Handler mHandler;

    public MyHandlerThread(String name) {
        super(name);
    }

    public Handler getHandler() {
        return mHandler;
    }

    @Override
    public void start() {
        super.start();
        Looper looper = getLooper(); // will block until thread's Looper object is
initialized
        mHandler = new Handler(looper) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    // process messages here
                }
            }
        };
    }
}

Since the handler is created in the start() method instead of in the run() method, it will be available (via a call to getHandler()) after the start() method returns without any race condition.

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

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