Specifics on using Looper.prepare() in Android

atheaos picture atheaos · Jul 13, 2011 · Viewed 11.3k times · Source

I'm having a bit of trouble understanding how to use the Looper prepare()/loop()/quit() logic.

I have three threads: one is the UI thread, one is a game logic thread and the last is a network communication thread (a background thread, lives only while being used).

The game thread has many dependencies on the results of the network calls, so I wanted to spin the network thread off of the game thread and have a Handler post the result back.

Of course, since the UI thread is not involved I need to call Looper.prepare()... somewhere. I thought it should be called in the game thread, but I can't do that because loop() takes it over.

How do I go about posting back to the game thread from network thread with my handler?

Answer

cyngus picture cyngus · Jul 22, 2011

What's going on is that once you call Looper.prepare() followed by Looper.loop() on a Thread, all that Thread will ever do is service its MessageQueue until someone calls quit() on its Looper.

The other thing to realize is that, by default, when a Handler is instantiated, it's code will always execute on the Thread it was created on

What you should do is create a new Thread and in run() call Looper.prepare(), setup any Handlers, and then call Looper.loop().

Bearing these things in mind here is the basic pattern I use a lot of places. Also, there's a good chance you should just be using AsyncTask instead.

public class NetworkThread extends Thread {
    private Handler mHandler;
    private Handler mCallback;
    private int QUIT = 0;
    private int DOWNLOAD_FILE = 1;
    public NetworkThread(Handler onDownloaded) {
        mCallback = onDownloaded;
    }

    public void run() {
        Looper.prepare();
        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    // things that this thread should do
                    case QUIT:
                        Looper.myLooper().quit();
                        break;
                    case DOWNLOAD_FILE:
                        // download the file
                        mCallback.sendMessage(/*result is ready*/);
                }
            }
        }
        Looper.loop();
    }

    public void stopWorking() {
        // construct message to send to mHandler that causes it to call 
        // Looper.myLooper().quit
    }

    public void downloadFile(String url) {
        // construct a message to send to mHandler that will cause it to
        // download the file
    }
}