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 :)
Related
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.
handler is passed as this:
public void getUserYouTubeFeed() {
new Thread(new GetYouTubeUserVideosTask(responseHandler, username, i)).start();
}
Handler responseHandler = new Handler() {
public void handleMessage(Message msg) {
populateListWithVideos(msg);
}
};
and in the run method of thread
public class GetYouTubeUserVideosTask implements Runnable {
// A handler that will be notified when the task is finished
private final Handler replyTo;
public GetYouTubeUserVideosTask(Handler replyTo, String username, int frag) {
this.replyTo = replyTo;
}
#Override
public void run() {
// some code here
Library lib = new Library(username, videos);
// Pack the Library into the bundle to send back to the Activity
Bundle data = new Bundle();
data.putSerializable(LIBRARY, lib);
// Send the Bundle of data (our Library) back to the handler (our Activity)
//Message msg = Message.obtain();
Message msg = new Message();
msg.setData(data);
// getting null pointer exception here
replyTo.sendMessage(msg);
}
}
had this same issue. I wanted to create a client thread class in a separate .java file. In order to work, however, it would need to know the handler of the main UI thread. Unfortunately, since Java does not support pointers, passing the handler from the UI to your custom class and assigning it:
public GetYouTubeUserVideosTask(Handler replyTo, String username, int frag) {
this.replyTo = replyTo;
}
simply creates a copy of the handler and associates it with your thread (not a link to the main UI handler).
Messages sent to a thread (or main UI) require a Looper which dispatches the messages from the message queue, which then can be processed by the message handler. The main UI has a message loop associated with it by default, accessed through Looper.getMainLooper() and, therefore, you can simply create a handler in your main UI which threads can post to. Threads, however, don't have a message loop by default, so when you try to call:
replyTo.sendMessage(msg); // NullPointerException
you are actually trying to send the message to your new thread's handler which doesn't have a message loop associated with it causing the exception.
You can look at the Looper documentation to see how to create a message loop for you thread, but remember: the looper and the handler in your thread ONLY handle messages TO your thread (this is how you can communicate between threads).
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.
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()
I have an app with a two threads - main and data loader. When data loader finishes it posts a Runnable object to the main thread (as described in the DevGuide), but it never gets delivered and run.
Here's the basic code:
class MyApp extends Application
{
public void onCreate()
{
LoaderThread t = new LoaderThread();
t.start();
}
private class LoaderThread extends Thread
{
public void run()
{
SystemClock.sleep(2000);
boolean res = m_handler.post(m_runnable);
if(res)
Log.d(TAG, "Posted Runnable");
}
}
private final Handler m_handler = new Handler();
private final Runnable m_runnable = new Runnable() {
public void run()
{
Log.d(TAG, "Hey, i'm runnable!");
}
}
}
Also it maybe important to note that I ran this code as a unit-test derived from an ApplicationTestCase:
class MyAppTest : public ApplicationTestCase
{
public MyAppTest()
{
super(MyApp.class);
}
public void testLoading()
{
createApplication();
// few asserts follow here...
}
}
So this fails. Runnable never gets run() called, although the log indicates that it has been posted successfully.
I also tried to send simple messages instead of posting runnable (m_handler.sendEmptyMessage(1) for example) - they never get delivered to handler's callback in the main thread.
What do I miss here?
Thanks in advance :)
A Handler requires a Looper in order to work. The Looper provides a message queue required by the Handler.
All instances of Activity have a Looper as one is used to process UI Events, but you can create your instance of Looper elsewhere.
Have a look in your Log output to see if Android is complaining about the absence of a Looper.
If it is, you might be able to fix by add the following to the top of your onCreate() method:
Looper.prepare();
m_handler = new Handler();
Looper.run();
And remove the initialisation of m_handler from later in your code.
Handler only works in an Activity AFAIK. You are attempting to use it in an Application.
An alternative to calling Looper.prepare() is to call new Handler(Looper.getMainLooper()). The problem with calling Looper.prepare() is that it will throw an exception when there is already a looper on your thread. Chances are you are writing code that has to run under different environments and this solution will handle more cases.
See:
AsyncTask and Looper.prepare() error