处理程序(Handler)是线程吗?Looper在处理程序和线程中扮演什么角色?

3

一个Handler是不是一个线程?如果是,我们如何从这个Handler(线程)更新UI?

如果我们使用Looper的概念,可能是可行的。在这种情况下,它适用于任何线程吗?我对这些线程、Handlers和Loopers非常困惑。有没有人可以举个例子来解释一下呢?

一个Handler是不是一个线程?如果是,我们如何从这个Handler(线程)更新UI?

如果我们使用Looper的概念,可能是可行的。在这种情况下,它适用于任何线程吗?我对这些线程、Handlers和Loopers非常困惑。有没有人可以举个例子来解释一下呢?


这个问题 "Thread和Handler之间的区别是什么" 只涉及到Handlers和Threads,但没有解释Loopers及其行为。而被接受的答案说"Handlers是后台线程,允许您与UI线程通信(更新UI)",但根据下面"ben75"的答案,Handler并不是一个线程。因此,我认为这不是那个问题的重复。


2
http://developer.android.com/reference/android/os/Handler.html - Blackbelt
那个问题只涉及到Handler和Thread,但没有解释Looper及其行为。 - jettimadhuChowdary
@jettimadhuChowdary - 在投票重新开放之前,请查看答案并确定它们是否已充分回答了您的问题。 - rayryeng
2个回答

7

前提: Handler不是线程。

Looper是与其创建的Thread相关联的对象。从它的名称可以猜到,Looper将循环执行某些操作,但是循环执行什么?它会循环执行与同一线程相关联的消息队列

接下来的问题是:我如何将某些内容放入这个消息队列中?

这就是Handler的作用。一个Handler总是与一个Looper相关联(哪一个?我们稍后会看到)。Handler可以扮演两个角色(这可能就是为什么它很容易混淆的原因)。

Handler的第一个作用:你必须使用它将消息发布到与其关联的Looper(实际上是其消息队列)。您可以使用各种Handler.sendMessage*(或Handler.post*)方法来完成这一点。(请注意,sendMessageDelayed/postDelayed方法允许您在未来发布Message/Runnable以进行处理)。

与Handler相关联的Looper是什么?非常简单:如果不指定,则为当前线程的Looper;但是您可以使用具有Looper的构造函数:{{link3:new Handler(Looper looper)}},在这种情况下,处理程序与参数中的looper相关联。

此时,我们知道:

  • 一个 Looper 与一个 Thread 相关联
  • 一个 Looper 循环遍历它的相关消息队列
  • 因此:只要我们为 Thread 拥有了一个 Looper,就会有一个消息队列与之相关联
  • 一个 Handler 总是与一个 Looper 相关联
  • 一个 Handler 可以用于将消息发布到消息队列中

现在,让我们看看第二部分:消息处理/消息处理。
首先,让我们看一下Looper循环遍历其消息队列
队列中有消息吗?是的(即某个Handler已发布它)。 是否到了处理此消息的时间(如果使用postDelayed发布)?如果不是,请稍等。如果是时候了:让我们分派这个消息。
记住我说过Handler有两个角色...这里是Handler的第二个角色:Handler(如其名称所示)可以处理消息。为了能够处理自定义消息,您必须子类化Handler类并实现handleMessage(Message)方法。
因此,Looper 将简单地调用发布消息的 Handler 的 handleMessage,它的工作(即分发消息)完成后(Looper 可以继续处理队列中的下一条消息)。
此时,您可能会问自己:“好吧,我看到延迟消息的好处了,但为什么我要为立即执行的任务使用所有这些东西呢?”
请记住,Looper 与一个线程相关联,并且将在该线程中调用 handleMessage。另一方面,Handler.post* 可以从另一个线程调用。因此,如果要从线程 Y 中的线程 X 安排作业,则此机制也非常方便。(如果作业影响 UI 并且必须在 UI 线程中运行,则特别有用)
最后注意:
  • UI 线程是一等公民:
在 Android 上,有一个与主线程(即 UI 线程)相关联的主 Looper。您可以使用 Looper.getMainLooper() 获取对它的引用,因此您可以创建与主 Looper 相关联的 Handler:
Handler myHandler = new Handler(Looper.getMainLooper());

使用此方法,您可以从任何线程向UI线程发布消息

  • 你真的需要使用消息和子类化Handler来使用它吗?不一定(并非总是需要)

您不必始终显式创建消息以使用此机制。您可以轻松地将{{link1:Runnable}}发布到Handler中,在这种情况下,您甚至不需要覆盖handleMessage(Message),因为处理程序的默认实现将简单地执行Runnable(在幕后:创建一个message,其中包含与其关联的Runnable)

  • Looper必须准备好(接收消息)

默认情况下,每个线程上都没有Looper(默认情况下,仅在UI-Thread上准备了一个)。要为当前线程准备Looper:调用{{link3:Looper.prepare()}}。


这太棒了...感谢@ben75提供这个清晰的解释。 - pokche

0

Handler:

处理程序允许您发送和处理与线程的消息队列相关联的消息和可运行对象。每个处理程序实例都与单个线程及其消息队列相关联。创建新处理程序时,它绑定到创建它的线程/消息队列 - 从那时起,它将向该消息队列传递消息和可运行项,并在它们从消息队列中出来时执行它们。

现在,如果您想从不是主线程的其他线程更新UI,则首先在主线程中创建一个Handler并将其传递到任何后台线程。在后台线程中,您将使用post(Runnable r)方法将消息发送回到主线程,因为(请阅读上面的段落):) Handler不是线程。

Thread:

线程是程序中的执行线程。

只是一般的后台处理任务。

Looper:

Looper是一个类,用于在队列中执行消息(Runnables)。普通线程没有这样的队列,例如简单线程没有任何队列。它只执行一次,在方法执行完成后,线程将不会运行另一个消息(Runnable)。
来源:
Looper的目的及如何使用?
Thread和Handler之间的区别是什么?

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