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

时间:2012-12-25 12:10:32

标签: android android-handler

问题是,我告诉我的主题使用 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();
    }
}

3 个答案:

答案 0 :(得分:4)

要更好地理解,请创建一个正常的Thread并尝试在该线程的Handler方法中创建run()。你会得到RuntimeException的说法:

  

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

现在在创建run()之前在Handler方法中调用Looper.prepare()会创建与调用线程相关联的新Looper对象 。您混淆的原因是Looper.prepare()不会将Thread作为参数。它不需要,因为它是一个静态方法,它在内部获取当前正在运行的线程的ThreadLocal。最多只有一个Looper与任何Thread相关联。

现在,通过内部呼叫new Handler(),调用Handler会将新的Looper对象与当前Thread的{​​{1}}相关联。您可以在同一个线程中使用自己的Callback创建多个Looper.myLooper()。所有处理程序都会从​​同一Handler的消息队列中获取消息。

答案 1 :(得分:4)

  

问题是,我告诉我的线程使用mHandler   打环器?

您不需要明确告诉它,因为系统(框架)会为您完成。实例化Handler时,它将自动获得对当前Thread的消息队列的访问权限。引用你的评论:

  

系统如何知道将邮件发送到mHandler Handler

我将在下面详述。

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

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

如您所见,首先它会获得您当前Looper的{​​{1}}。 Thread的源代码如下:

Looper.myLooper()

它从线程本地存储中获取它。之后,当您使用此public static final Looper myLooper() { return (Looper)sThreadLocal.get(); } 发送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); } 实例设置为Handler的目标。因此,稍后,当调度Message时,它将包含Message作为其目标。这就是Handler将知道它应该将哪个Looper发送给它的方式。详细信息,当您调用Handler时,队列中的每个Looper.loop()个实例都会发生以下情况:

Message

msg.target.dispatchMessage(msg); 代码如下:

dispatchMessage()

请注意上次 public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } 来电 - 这正是您的handleMessage(msg)覆盖!

答案 2 :(得分:2)

你什么都没说。来自Handler文档:

  

每个Handler实例都与一个线程相关联   线程的消息队列。当您创建新的Handler时,它将被绑定   正在创建它的线程的线程/消息队列 - 来自   那一点,它将为该消息传递消息和可运行的消息   队列并在它们从消息队列中出来时执行它们。

处理程序自动绑定到线程的消息队列。您只实现回调,而系统将负责所有事情,即调度和处理消息。实际上我同意,使用两个静态方法,如Looper.prepare()Looper.loop()并自动推断事物,使模式感觉像黑魔法:)