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

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

当你完成所有在线程调用“handler”上执行的任务之后,执行所有在处理程序中线程操作之后需要执行的任务……!!! 我是否符合你的要求? - Sam-In-TechValens
3个回答

6
问题是,我应该在哪里告诉我的线程使用mHandler来运行循环程序?
您不需要明确告诉它,因为系统(框架)会自动为您完成。当您实例化Handler时,它将自动获取对当前线程的消息队列的访问权限。引用您的评论:
系统如何知道将消息发送到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;

正如您所看到的,首先它获取当前线程的LooperLooper.myLooper()的源代码如下:

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

它从线程本地存储中获取它。稍后,当您使用此Handler发送Message时,Handler实际上将自己设置为Message的接收者:这就是Looper在到达Message时要分派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)重写!


非常感谢。现在我和大家都能理解它了。 - Aminadav Glickshtein
嗨@ThomasCalc,你能帮忙回答这个问题吗:http://stackoverflow.com/questions/31914966/how-to-get-the-amount-of-specified-message-which-not-handled-by-handler-in-andro - Jerikc XIONG

5
为了更好地理解,可以创建一个普通的Thread,并尝试在该线程的run()方法中创建一个Handler。您将会收到一个RuntimeException,提示:

无法在没有调用Looper.prepare()的线程中创建处理程序

现在,在创建Handler之前,在run()方法中调用Looper.prepare()将创建一个与调用线程关联的新Looper对象。您困惑的来源在于Looper.prepare()不需要以Thread作为参数。由于它是一个静态方法,因此内部获取当前正在运行线程的ThreadLocal。任何Thread最多只能关联一个Looper
现在,调用new Handler()将通过内部调用Looper.myLooper()将新的Handler对象与当前ThreadLooper相关联。您可以在同一线程中创建多个具有其自己回调的Handler。所有的处理程序都将从同一Looper的消息队列中获取它们的消息。

3
您不需要做任何事情。来自Handler文档的内容如下:
每个Handler实例都与单个线程及其消息队列相关联。当您创建一个新的Handler时,它会绑定到创建它的线程/消息队列-从那时起,它将向该消息队列传递消息和可运行项,并在它们从消息队列中出来时执行它们。
处理程序自动绑定到线程的消息队列。您只需实现回调函数,系统就会负责一切,即调度和处理消息。实际上,我同意使用两个静态方法Looper.prepare()Looper.loop(),并自动推断事物,使模式感觉像黑魔法 :)

但是,我可以将mHandler更改为其他名称吗?系统如何知道将消息发送到mHandler处理程序? - Aminadav Glickshtein
你可以随意命名。由于调用了 Looper 方法,系统会知道与 Handler 相关的 线程。但是 Handler,您必须自己指定。如果您告诉我您的应用程序要做什么,我可以举例说明以便更好地理解。 - Raffaele

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接