Android 2.1: Multiple Handlers in a Single Activity - android

I've more than one Handlers in an Activity. I create all the handlers in the onCreate() of the main activity. My understanding is the handleMessage() method of each handler will never be called at the same time because all messages are put in the same queue (the Activity thread MessageQueue). Therefore, they will be executed in the order in which are put into the Queue. They will also be executed in the main activity thread. Is this correct ?
public void onCreate() {
this.handler1 = new Handler() {
#Override
public void handleMessage(Message msg) {
//operation 1 : some operation with instanceVariable1
super.handleMessage(msg);
}
};
this.handler2 = new Handler() {
#Override
public void handleMessage(Message msg) {
//Operation 2: some operation with instanceVariable1
super.handleMessage(msg);
}
};
this.handler3 = new Handler() {
#Override
public void handleMessage(Message msg) {
//Operation 3: some operation with instanceVariable1
super.handleMessage(msg);
}
};
}

From the docs "When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue."
So you're right, they will run in the order that you queue them on the UI thread (since you are going to create them in onCreate).

One message per time, and per thread, and per handler.
Every new Handler(...) instance is bound, explicitly or implicitly, to Looper instance, and only once.
Looper instance, is already created somewhere with Looper.prepare() call
//usually obtained by Activity.getMainLooper() or Looper.myLooper()
Looper.prepare() uses ThreadLocal variable sThreadLocal (static field) to have one Looper instance per thread.
( It works same like hashMap.put(Thread.getCurrent(), new Looper()) )
every looper has its own private MessageQueue
every Looper instance has its main method loop()
loop(){
while(true){
Message msg = messageQueue.next();
msg.target.dispatchMessage(msg);
}
}
every message have a (Handler) target is set, and exception is thrown(within MessageQueue.enqueueMessage()) if it does not.
since Handler cannot be bound to several Loopers is does so every handler receives only one message at time and only with msg.target==handler
so sendMessage() or postMessage() works something like this:
handler.post(Message msg){
Looper.sThreadLocal.get(Thread.getCurrent()).messageQueue.push(msg);
}
so call stack , while handle message, should look something like this:
Looper.myLooper()-> Thread.getCurrent()-> Looper-> MessageQueue.next()-> Message-> Message.target-> Handler-> dispatchMessage()-> handleMessage()

Related

What happens if a Handler posts a message to a thread after Looper.prepare() but before Looper.loop() has been called?

Consider the following snippet:
Looper.prepare();
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
getLooper().quitSafely();
}
};
for(int i = 0; i < urls.size(); i++) {
useCaseProvider.get().execute(callback, handler, urls.get(i), threadPool);
}
Looper.loop();
//Continue processing the results of all the use cases after the
//loop has been asked to terminated via the handler
A little background: I'm doing some processing on the UI thread where I will need to ping a large about of devices and do something with the result. I need to perform the requests in parallel to be efficient.
Question: If one of these use cases somehow executed fast enough and made a callback before I was able to hit Looper.loop(); would the message be queued or just lost? Callbacks are being posted back to this thread by the handler posting a runnable to the original thread.
Assuming you have invoked Looper.prepare() prior to your useCaseProvider delivering results, you should be fine.
If Looper.prepare was not called you should be seeing RuntimeException being thrown.
The Looper object is tied to a thread local which hosts the message queue. The Looper.prepare function will construct this message queue at which point you can begin queuing up messages. Once you fire Looper.loop() that's when those pending messages will begin to execute.
Looking at the snippet, I'm not too sure how things are tied together.
Generally you want to construct a looper like this:
private static final class MyThread extends Thread {
private Handler mHandler;
#Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// handle message
}
};
Looper.loop();
}
public Handler getHandler() {
return mHandler;
}
}
I'm assuming your thread pool is then a pool of MyThread threads, each of which have their own Looper. The thread pool should initialize your threads so once you deliver a Runnable to be executed by your thread, the run() method should have the Looper initialized.
On the other hand, if you wish to associate your Handler with a particular looper (ie. you are not constructing the Handler within a thread like above) then you should be passing the Looper thread in to the constructor like:
Handler h = new Handler(myLooperThread);
If you don't specify that, then the handler uses the thread in which it was created to grab that thread's Looper from the ThreadLocal object.
Lastly if your intentions are to have messages delivered on the Handler which is associated with the UI thread then you should not be concerned about calling Looper.prepare or Looper.loop. This is handled by the Activity.

What causes Looper.Loop() to hang (i.e. never return)

I'm a little confused about something. Basically, I'm spawning a thread, and in addition I want to run a message loop in that thread. I'm basically doing the following:
This is straight out of the Android Looper class API documentation. However, my application always gets stuck at Looper.loop() and never returns from it. My current work around for this, is to just create a handler in the main thread (or UI thread) and send messages to that thread instead. However, for the sake of cleanliness and to just make the flow of my application make sense, I'd much rather send my messages to the thread I'm creating.
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
// The rest of the code below is a control loop
}
}
Any thoughts on what might cause Looper.loop() to never return?
Looper.loop creates an infinite loop and only stops when you call quit
http://developer.android.com/reference/android/os/Looper.html#loop()
This may work
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
while(true){
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
}
// The rest of the code below is a control loop
}
}

How the Looper knows to send the message to Handler?

The question is, where I tell my Thread to use mHandler for the Looper?
Thank you.
I am using the below code:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
The question is, where I tell my Thread to use mHandler for the
Looper?
You don't need to tell it explicitly, because the system (framework) does it for you. When you instantiate the Handler, it will automatically obtain access to the message queue of your current Thread. Quoting your comment:
How the system know to send the message to the mHandler Handler?
I'll detail it below.
This is the constructor of android.os.Handler in Android:
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
As you can see, first it obtains the Looper of your current Thread. The source code of Looper.myLooper() is as follows:
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
It obtains it from the thread local storage. Later, when you send a Message with this Handler, the Handler actually sets itself as the recipient of the Message: this is how the Looper will know where to dispatch the Message when it arrives. In details:
When you call mHandler.sendMessage(), eventually this code runs (among many other code lines):
MessageQueue queue = mQueue;
boolean sent = false;
if (queue != null) {
msg.target = this; // msg is your Message instance
sent = queue.enqueueMessage(msg, uptimeMillis);
}
As you can see, it sets the Handler instance as the target of the Message. So, later, when the Message is dispatched, it will contain the Handler as its target. This is how the Looper will know which Handler it should dispatch it to. In details, when you call Looper.loop(), the following happens for each of your Message instances in the queue:
msg.target.dispatchMessage(msg);
The dispatchMessage() code is the following:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Notice the last handleMessage(msg) call -- this is exactly your handleMessage(msg) override!
To have a better understanding, create a normal Thread and try creating a Handler in the run() method of that thread. You'll get a RuntimeException saying:
Can't create handler inside thread that has not called
Looper.prepare()
Now calling Looper.prepare() in the run() method before creating a Handler would create a new Looper object associated with the calling thread. The source of your confusion is that Looper.prepare() does not take a Thread as argument. It need not, since it's a static method, which internally gets the ThreadLocal of the currently running thread. There can be at most one Looper associated with any Thread.
Now, calling new Handler() would associate the new Handler object with the Looper of the current Thread by internally calling Looper.myLooper(). You can create more than one Handler each with its own Callback in the same Thread. All Handlers would get their messages from the message queue of the same Looper.
You don't tell anything. From the Handler documentation:
Each Handler instance is associated with a single thread and that
thread's message queue. When you create a new Handler, it is bound to
the thread / message queue of the thread that is creating it - from
that point on, it will deliver messages and runnables to that message
queue and execute them as they come out of the message queue.
The handler is automatically bound to the thread's message queue. You only implement the callback, and the system will take care of everything, ie dispatching and processing the messages. Actually I agree that, using two static methods like Looper.prepare() and Looper.loop() and automatically infer things, makes the pattern feels like black magic :)

Message handlers

I have a thread, initialthread that executes a task every n seconds. This is enclosed in activity A. i have a message handler on activity B.
mHandler = new Handler(){
public void handleMessage(Message msg)
{
//perform task
executetask();
}
};
Will this handler excutetask() whenever the initialthread finishes executing??
thanks
It will execute whenever you pass the massage from the initial thread.
I mean whenever you call .sentMessage() from the initial thread.

How does Android/DalvikVM process Handlers?

I'm wondering how Handlers are processed in Android/DalvikVM. I'm writing an application for Android, and in one class I have a Handler method which receives messages from another class. Will the Handler method act as a Thread and be asynchronous to the run() method in the same class, or will it wait until a line of code in the run() method is finished (sort of atomic operation)? Or something else?
I'm wondering, because I want to add messages to a queue in the Handler method, and process and remove them in the run() method (producer-consumer).
My code structure:
public class Parser implements Runnable {
public void run() {
while(true) {
// Remove a byte from the ring buffer and parse it
byte b = Ringbuffer_read();
// Parse
try {
Thread.sleep(40);
} catch (InterruptedException e) {}
}
}
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
// Store all the received bytes in the ring buffer
for (int i = 0; i < msg.arg1; i++) {
Ringbuffer_store(((byte[]) msg.obj)[i]);
}
break;
}
}
};
}
When will the code in the handler run? Does it interrupt the code in the run() method at any point? Do I have to have some synchronization or semaphores or something around the code in the run() and handler method so that I don't corrupt my buffer?
An Android Handler associates itself with whatever thread it is created in (assuming that thread has a looper already). By default in Android callbacks run on a thread named "main" which is also called the ui thread. Regardless of what thread the post method is called from the handleMessage method will be called from the thread that the Handler was created in (usually the "main" thread). Because the handleMessage method is always called in the same thread, only one message will be processed at a time.
If your plan is to have only a single consumer then Handler is a good choice. You will not need to remove messages from your consumer (the Handler), instead they will simply arrive in handleMessage for processing. If you want to do processing on the "main" thread then you just make a new Handler, if you want to do processing in the background to avoid ANRs you will likely want to use HandlerThread. Here's an example of a Handler running on it's own background thread:
HandlerThread handlerThread = new HandlerThread("Consumer");
handlerThread.start();
Handler consumer = new Handler(handlerThread.getLooper()) {
public void handleMessage (Message msg) {
}
};
Notice that in the description above class does not come into play at all because classes are how code is structured which is unrelated to what thread the code is executed on.

Categories

Resources