5

问题是,我在哪里告诉我的线程将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();
    }
}
4

3 回答 3

5

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

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

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

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

于 2012-12-25T13:02:16.420 回答
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;

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

public static final Looper myLooper() {
    return (Looper)sThreadLocal.get();
}

它从线程本地存储中获取它。Message稍后,当您使用 this发送 a时HandlerHandler实际将自己设置为 的接收者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)调用——这正是你的handleMessage(msg)覆盖!

于 2012-12-25T13:39:53.100 回答
3

你什么都不说。从Handler文档中:

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

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

于 2012-12-25T12:22:38.800 回答