How the Looper knows to send the message to Handler?

橙三吉。 提交于 2019-12-21 17:28:43

问题


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();
    }
}

回答1:


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!




回答2:


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.




回答3:


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 :)



来源:https://stackoverflow.com/questions/14030534/how-the-looper-knows-to-send-the-message-to-handler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!