Looper 如何知道将消息发送给 Handler?

Ami*_*ein 5 android android-handler

问题是,我在哪里告诉我的 Thread 将mHandler用于Looper

谢谢你。我正在使用以下代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Dhe*_*.S. 5

为了更好地理解,创建一个法线Thread并尝试Handler在该run()线程的方法中创建一个。你会得到RuntimeException一句话:

无法在未调用的线程内创建处理程序 Looper.prepare()

现在run()在创建 a 之前在方法中调用 Looper.prepare()Handler将创建一个与调用线程关联的新Looper对象。您困惑的根源在于 Looper.prepare() 不接受 a作为参数。它不需要,因为它是一个静态方法,它在内部获取当前正在运行的线程的 。最多可以有一个与 any 相关联。ThreadThreadLocalLooperThread

现在,调用new Handler()将通过内部调用将新Handler对象与Looper当前对象相关联。您可以在同一个线程中创建多个,每个都有自己的回调。所有处理程序将从相同的消息队列中获取它们的消息。ThreadLooper.myLooper()HandlerLooper


Tho*_*alc 5

问题是,我在哪里告诉我的线程将 mHandler 用于 Looper?

您不需要明确告诉它,因为系统(框架)会为您完成。当您实例化 时Handler,它会自动获取对您当前Thread. 引用你的评论:

系统如何知道将消息发送到mHandler Handler?

下面我详细说一下。

这是android.os.HandlerAndroid中的构造函数:

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
Run Code Online (Sandbox Code Playgroud)

如您所见,它首先获取Looper您当前的Thread. 的源代码Looper.myLooper()如下:

public static final Looper myLooper() {
    return (Looper)sThreadLocal.get();
}
Run Code Online (Sandbox Code Playgroud)

它从线程本地存储中获取它。后来,当您发送Message与此Handler,在Handler实际本身设置为收件人Message:这是怎么Looper会知道去哪里派遣Message到达时。详细说明:

当您调用 时mHandler.sendMessage(),最终会运行此代码(在许多其他代码行中):

    MessageQueue queue = mQueue;
    boolean sent = false;
    if (queue != null) {
        msg.target = this; // msg is your Message instance
        sent = queue.enqueueMessage(msg, uptimeMillis);
    }
Run Code Online (Sandbox Code Playgroud)

如您所见,它将Handler实例设置为Message. 因此,稍后,当Message被分派时,它将包含Handler作为其目标。这就是Looperwill 知道Handler它应该将它发送到哪个的方式。详细地说,当您调用 时Looper.loop()Message队列中的每个实例都会发生以下情况:

msg.target.dispatchMessage(msg);
Run Code Online (Sandbox Code Playgroud)

dispatchMessage()代码如下:

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}
Run Code Online (Sandbox Code Playgroud)

注意最后一次 handleMessage(msg)调用——这正是您的handleMessage(msg)覆盖!