Search code examples
androidmultithreadinghandlerlooper

Handlers initialized with Looper.getMainLooper() does not respond to message callbacks


I am trying to implement Handlers listening on the same Looper from different threads.

Below I have two Handlers, one created in the main thread, another in the child thread, however both are initialized to listen on the Main Looper.

private Handler mMain;
public static final ThreadPoolExecutor tpe =
        (ThreadPoolExecutor) Executors.newCachedThreadPool();

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mMain = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            Log.wtf("", "main:" + msg);
        }
    };

    tpe.execute(new Runnable() {
        private Handler tChild = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                Log.wtf("", "child:" + msg);
            }
        };

        @Override
        public void run() {
            Log.wtf("", "send msg to main looper");
            tChild.sendEmptyMessage(100);
        }
    });
}

But when I send a message like below, only the child handler prints the message. The main handler does not receive the message.

03-20 22:02:26.754: A/(12857): send msg to main looper
03-20 22:02:26.847: A/(12857): child:{ what=100 when=-8ms }

What am I doing wrong? Thank you for reading.


Solution

  • Each Handler instance controls the Message target and there is no way to get them to share, so every message or post sent to a Handler is only executed by that instance.

    The Looper indicates which thread the messages/runnables sent will be executed on. In your code, both Handlers will execute handleMessage() on the main thread, despite being created on separate threads. That is the real reason you can pass a Looper instance to a Handler...if you pass no Looper, then the Handler will execute code on the thread in which it was created (which must also be a Looper thread).

    Furthermore, because of this there isn't reason to create multiple Handlers to post data in this manner. A single Handler is designed to be sent messages from multiple threads, and they are all serialized in a MessageQueue and executed on the chosen Looper thread. You can post directly to mMain from the background thread to execute code on that thread. In this case, passing the Looper is redundant at that code is already on the main thread.