Android中的Looper,Handler和MessageQueue之间有什么关系?

Bla*_*ake 95 android message-queue handler looper

我查了官方的Android文档/指南Looper,HandlerMessageQueue.但我无法得到它.我是android新手,对这些概念非常困惑.

Ted*_*opp 102

A Looper是一个消息处理循环:它从a读取和处理项目MessageQueue.所述Looper类通常是在与结合使用HandlerThread(的一个子类Thread).

A Handler是一个实用程序类,Looper通过将消息和Runnable对象发布到线程来促进与主进行交互MessageQueue.当Handler被创建,它被绑定到特定的Looper(和相关联的线程和消息队列).

在典型用法中,您创建并启动a HandlerThread,然后创建一个Handler对象(或多个对象),其他线程可以通过该对象与HandlerThread实例进行交互.在Handler必须同时在运行中创建HandlerThread,虽然一度创造是没有限制什么的线程可以使用Handler的调度方法(post(Runnable)等)

在创建应用程序实例之前,Android应用程序中的主线程(也称为UI线程)被设置为处理程序线程.

除了类文档,有这一切的一个很好的讨论在这里.

  • @hqt - 糟糕.是的,它应该是`HandlerThread`.不敢相信它已经走了这么久没有人注意到我的错字.(现在修好了 - 谢谢!) (2认同)
  • @Jack - 他们是一回事.Android [MessageQueue`的API文档](https://developer.android.com/reference/android/os/MessageQueue.html)声明`MessageQueue`是一个"低级别的类,其中包含消息列表由"Looper`._"派遣 (2认同)

K_A*_*nas 94

众所周知,直接从android中主线程以外的线程更新UI组件是违法的.如果我们需要启动一个单独的线程来完成一些昂贵的工作并在完成后更新UI,那么这个Android文档(在UI线程中处理昂贵的操作)建议遵循的步骤.我们的想法是创建一个与主线程关联的Handler对象,并在适当的时候向其发布Runnable.这将在主线程上调用.此机制使用LooperHandler类实现.Runnable

Looper班保持的MessageQueue,其中包含一个列表的消息.Looper的一个重要特征是它与创建它的线程相关联.这种关联永远存在,不能破坏也不能改变.另外请注意,一个线程不能超过相关联的一个.为了保证这种关联,存储在线程局部存储中,并且不能通过其构造函数直接创建.创建它的唯一方法是调用prepare静态方法.prepare方法首先检查当前线程的ThreadLocal,以确保没有与该线程关联的Looper.检查后,创建并保存新的.准备好之后,我们可以在其上调用循环方法来检查新消息并且必须处理它们.LooperLooperLooperLooperLooperThreadLocalLooperHandler

如名称所示,Handler该类主要负责处理(添加,删除,调度)当前线程的消息MessageQueue.一个Handler实例也绑定到一个线程.Handler和Thread之间绑定是通过Looper和实现的MessageQueue.阿Handler始终绑定到一个Looper,并且随后绑定到相关的螺纹与所述Looper.与此不同Looper,多个Handler实例可以绑定到同一个线程.每当我们调用post或任何类似的方法时Handler,都会向相关联的消息添加新消息MessageQueue.消息的目标字段设置为当前Handler实例.当Looper收到此消息时,它会在消息的目标字段上调用dispatchMessage,以便消息路由回要处理的Handler实例,但是在正确的线程上.之间的关系Looper,HandlerMessageQueue显示如下:

在此输入图像描述

  • 谢谢!但是,如果处理程序首先将消息发布到消息队列然后**处理**来自同一队列的消息,那么重点是什么?为什么它不直接处理消息? (5认同)
  • @Blake b/c你是从一个线程(非looper线程)发布但在另一个线程(looper线程)中处理消息 (4认同)

김준호*_*김준호 75

让我们从Looper开始吧.当您了解Looper是什么时,您可以更轻松地理解Looper,Handler和MessageQueue之间的关系.您还可以更好地了解Looper在GUI框架中的作用.Looper是做两件事的.

1)Looper 将正常线程(在其run()方法返回时终止)转换为持续运行直到Android应用程序运行的内容,这在GUI框架中是必需的(从技术上讲,它仍然在run()方法返回时终止.但是让我澄清一下我的意思,下面).

2)Looper 提供了一个队列,其中要完成的作业被排队,这在GUI框架中也是必需的.

您可能知道,当启动应用程序时,系统会为应用程序创建一个执行线程,称为"main",而Android应用程序通常完全在单个线程上运行,默认情况下为"主线程".但主线程不是一些秘密,特殊线程.它只是一个普通的线程,您也可以使用new Thread()代码创建,这意味着它的run()方法返回时终止!想想下面的例子.

public class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }

    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,让我们将这个简单的原则应用于Android应用程序.如果Android应用程序在普通线程上运行会发生什么?一个名为"main"或"UI"的线程或任何启动应用程序的线程,并绘制所有UI.因此,第一个屏幕显示给用户.所以现在怎么办?主线程终止了吗?不,它不应该.它应该等到用户做某事,对吧?但是我们怎样才能实现这种行为呢?好吧,我们可以尝试Object.wait()Thread.sleep().例如,主线程完成其初始作业以显示第一个屏幕,然后休眠.当需要执行新工作时,它会唤醒,这意味着中断.到目前为止一切顺利,但此时我们需要一个类似队列的数据结构来保存多个作业.想想用户连续触摸屏幕的情况,任务需要更长的时间才能完成.因此,我们需要一个数据结构来保持以先进先出的方式完成的工作.此外,您可以想象,使用中断实现永远运行和进程的作业到达线程并不容易,并导致复杂且通常无法维护的代码.我们宁愿为此目的创建一个新机制,这就是Looper的意义所在.Looper类官方文档说,"默认情况下,线程没有与它们相关的消息循环",而Looper是一个"用于为线程运行消息循环"的类.现在你可以理解它的含义了.

让我们转到Handler和MessageQueue.首先,MessageQueue是我上面提到的队列.它驻留在Looper里面,就是这样.您可以使用Looper类的源代码进行检查.Looper类有一个MessageQueue的成员变量.

那么,什么是汉德勒?如果有一个队列,那么应该有一个方法可以让我们将新任务排入队列,对吗?这就是汉德勒的作用.我们可以使用各种post(Runnable r)方法将新任务排入队列(MessageQueue).而已.这完全是关于Looper,Handler和MessageQueue.

我的最后一句话是,所以基本上Looper是一个用于解决GUI框架中出现的问题的类.但是这种需求也可能在其他情况下发生.实际上它是一个非常着名的多线程应用程序模式,你可以在Doug Lea的"Concurrent Programming in Java"中了解它(特别是第4.1.4节"工作线程"会很有帮助).此外,您可以想象这种机制在Android框架中并不是唯一的,但是所有GUI框架可能都需要与此类似.您可以在Java Swing框架中找到几乎相同的机制.

  • 最佳答案。从此详细说明中了解到更多信息。我想知道是否有一些更详细的博客文章。 (2认同)

AnV*_*AnV 26

MessageQueue:它是一个低级类,包含要由a调度的消息列表Looper.消息不是直接添加到a MessageQueue,而是通过HandlerLooper.[ 3 ] 相关联的对象添加.

Looper:它遍历MessageQueue包含要分派的消息的a .管理队列的实际任务由Handler负责处理(添加,删除,调度)消息队列中的消息来完成.[ 2 ]

Handler:它允许您发送和处理MessageRunnable线程关联的对象MessageQueue.每个Handler实例都与一个线程和该线程的消息队列相关联.[ 4 ]

当你创建一个新的Handler,它被绑定到创建它的线程的线程/消息队列 - 从那时起,它将消息和runnables传递给该消息队列在它们从消息队列中出来时执行它们.

请注意下面的图片[ 2 ]以便更好地理解.

在此输入图像描述