题目:请解释下在单线程模型中 Message、Handler、Message Queue、Looper 之间的关系。
答案:
简单的说,Handler 获取当前线程中的 Looper 对象,Looper 用来从存放 Message 的MessageQueue 中取出 Message,再交由 Handler 进行 Message 的分发和处理。
基本概念
-
Message Queue(消息队列):
用来存放通过 Handler 发布的消息,通常附属于某一个创建它的线程,可以通过 Looper.myQueue()得到当前线程的消息队列。 -
Handler:
可以发布或者处理一个消息或者操作一个 Runnable,通过 Handler 发布消息,消息将只会发送到与它关联的消息队列,Handler也只能处理该消息队列中的消息。 -
Looper:
是 Handler 和消息队列之间通讯桥梁,程序组件首先通过 Handler 把消息传递给 Looper,Looper 把消息放入队列。Looper 也把消息队列里的消息广播给所有的Handler:Handler 接受到消息后调用 handleMessage 进行处理。 -
Message:
消息的类型,在 Handler 类中的 handleMessage 方法中得到单个的消息进行处理。
具体分析
在单线程模型下,为了线程通信问题,Android 设计了一个 Message Queue(消息队列), 线程间以通过该 Message Queue 并结合 Handler 和 Looper 组件进行信息交换。下面将对它们进行分别介绍:
-
Message
Message 消息,理解为线程间交流的信息,处理数据后台线程需要更新 UI,则发送 Message 内含一些数据给 UI 线程。
-
Handler
Handler 处理者,是 Message 的主要处理者,负责 Message 的发送,Message 内容的执行处理。后台线程就是通过传进来的 Handler 对象引用来sendMessage(Message)。
而使用 Handler,需要 implement 该类的handleMessage(Message)方法,它是处理这些 Message 的操作内容,例如Update UI。通常需要子类化 Handler 来实现handleMessage 方法。
-
Message Queue
Message Queue 消息队列,用来存放通过 Handler 发布的消息,按照先进先出执行。
每个 message queue 都会有一个对应的 Handler。Handler 会向 message queue 通过两种方法发送消息:sendMessage 或 post。这两种消息都会插在 message queue 队尾并按先进先出执行。
但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被 Handler 的 handleMessage()函数处理;而通过 post 方法发送的是一个 runnable 对象,则
会自己执行。
-
Looper
Looper 是每条线程里的 Message Queue 的管家。Android 没有 Global 的 Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。
所以调用 Looper.getMainLooper()得到的主线程的 Looper 不为 NULL,但调用 Looper.myLooper() 得到当前线程的 Looper 就有可能为 NULL。
对于子线程使用 Looper,API Doc 提供了正确的使用方法:这个 Message 机制的大概流程:
①在 Looper.loop()方法运行开始后,循环地按照接收顺序取出 Message Queue 里面的非 NULL的 Message。
② 一开始 Message Queue 里面的 Message 都是 NULL 的。当 Handler.sendMessage(Message)到Message Queue,该函数里面设置了那个 Message 对象的 target 属性是当前的 Handler 对象。随后 Looper 取出了那个 Message,则调用 该 Message 的 target 指向的 Hander 的 dispatchMessage函数对 Message 进行处理。
在 dispatchMessage 方法里,如何处理 Message 则由用户指定,三个判断,优先级从高到低:
a) Message 里面的 Callback,一个实现了 Runnable 接口的对象,其中 run 函数做处理工作;
b) Handler 里面的 mCallback 指向的一个实现了 Callback 接口的对象,由其 handleMessage进行处理;
c) 处理消息 Handler 对象对应的类继承并实现了其中 handleMessage 函数,通过这个实现的handleMessage 函数处理消息。
由此可见,我们实现的 handleMessage 方法是优先级最低的!
③ Handler 处理完该 Message (update UI) 后,Looper 则设置该 Message 为 NULL,以便回收!
在网上有很多文章讲述主线程和其他子线程如何交互,传送信息,最终谁来执行处理信息之类的,个人理解是最简单的方法——判断 Handler 对象里面的 Looper 对象是属于哪条线程的,则由该线程来执行!
①当 Handler 对象的构造函数的参数为空,则为当前所在线程的 Looper;
②Looper.getMainLooper()得到的是主线程的 Looper 对象,Looper.myLooper()得到的是当前线程的 Looper 对象。