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.
static Looper. getMainLooper() Returns the application's main looper, which lives in the main thread of the application. MessageQueue. getQueue()
Looper is a worker that keeps a thread alive, loops through MessageQueue and sends messages to the corresponding handler to process. Finally Thread gets terminated by calling Looper's quit() method.
Looper is an abstraction over event loop (infinite loop which drains queue with events) and Handler is an abstraction to put/remove events into/from queue with events (which is drained by Looper) and handle these events when they are processed.
Android Looper is a Java class within the Android user interface that together with the Handler class to process UI events such as button clicks, screen redraws and orientation switches. They may also be used to upload content to an HTTP service, resize images and execute remote requests.
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.
Messages sent to a Handler
will only be handled by that Handler
, even if it's sharing a Looper
.
Buried in the source code for Handler is the line
msg.target = this;
This ensures no other Handler
will touch it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With