本文主要介绍 Android 消息机制, 这里整理了消息机制的详细资料,和经常出现的问题,希望能帮助大家对消息机制的理解
Android 是一种基于 Linux 的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由 Google 公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用 "安卓" 或 "安致"。
Android 的消息机制几乎是面试必问的话题,当然也并不是因为面试,而去学习,更重要的是它在 Android 的开发中是必不可少的,占着举足轻重的地位,所以弄懂它是很有必要的。下面就来说说最基本的东西。
Looper
作用:
关联起 Thread
循环取出消息
1、Looper 是否可以直接实例化?
Looper 构造方法是私有的,其中做了两件事
创建一个 MessageQueue
得到与之对应的 Thread
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);
- mThread = Thread.currentThread();
- }
2、一个线程能对应多个 Lopper?
不能,一个线程对应一个 Looper 对象,通过 ThreadLocal 保证一个线程只有一个 Looper 与之对应,如果多次调用 Looper.prepare(); 则会抛出运行时异常。
- private static void prepare(boolean quitAllowed) {
- if (sThreadLocal.get() != null) { // 查看是否有looper与当前线程对应
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- sThreadLocal.set(new Looper(quitAllowed));
- }
3、Looper 是无限循环,会阻塞吗?
是,当开启一个 loop 后是一个死循环,从 MessageQueue 中取出消息,处理消息,但是也有可能退出,在没有消息后退出循环。
- public static void loop() {
- final Looper me = myLooper();
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
- final MessageQueue queue = me.mQueue;
- // 略
- for (;;) {
- Message msg = queue.next(); // might block
- if (msg == null) { // 当没有消息的时候,退出
- // No message indicates that the message queue is quitting.
- return;
- }
- // 略
- msg.target.dispatchMessage(msg);
- }
4、可以再次调用 Looper.prepareMainLooper 吗?
不可以,Looper.prepareMainLooper 最终也是调用 prepare(),同 2.
- public static void prepareMainLooper() {
- prepare(false); // 创建一个Looper
- synchronized (Looper.class) {
- if (sMainLooper != null) {
- throw new IllegalStateException("The main Looper has already been prepared.");
- }
- sMainLooper = myLooper();
- }
- }
5、MainLooper 什么时候创建的?
MainLooper 是启动 Activity 创建 ActivityThread(并不是一个 Thread) 时候创建,所以不能多次创建。
- public static void main(String[] args) {
- // 略
- Process.setArgV0("<pre-initialized>");
- Looper.prepareMainLooper();
- // 略
- ActivityThread thread = new ActivityThread();
- thread.attach(false);
- // 略
- if (sMainThreadHandler == null) {
- sMainThreadHandler = thread.getHandler();
- }
- // 略
- Looper.loop();
- throw new RuntimeException("Main thread loop unexpectedly exited");
- }
- }
Handler
作用:
发送消息到 MessageQueue
处理消息
1、Handler 如何与 Looper、MessageQueue 关联起来?
我们知道一个 Looper 对应一个 Thread,一个 Looper 包含一个 MessageQueue。当我们创建 Handler 时就会从当前线程中取出与之对应的 Looper,让后在从 Looper 中取出 MessageQueue。
- // 1、自动获取
- public Handler(Callback callback, boolean async) {
- // 略
- mLooper = Looper.myLooper(); // 取出当前线程中的Looper
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread that has not called Looper.prepare()");
- }
- mQueue = mLooper.mQueue; // 取出MessageQueue
- mCallback = callback;
- mAsynchronous = async;
- }
- // 2、传递一个Looper进来
- public Handler(Looper looper, Callback callback, boolean async) {
- mLooper = looper;
- mQueue = looper.mQueue;
- mCallback = callback;
- mAsynchronous = async;
- }
Message
单项链表结构。
作用:
数据的载体
1、消息如何复用的?
从全局消息池 (链表结构) 中
- public static Message obtain() {
- synchronized (sPoolSync) {
- if (sPool != null) {
- Message m = sPool;
- sPool = m.next;
- m.next = null;
- m.flags = 0; // clear in-use flag
- sPoolSize--;
- return m;
- }
- }
- return new Message();
- }
2、Message 为什么能传递?
Android 中想要传递对象要么实现 Serializable 要么 Parcelable,在这里是实现了 Parcelable 接口。
public final class Message implements Parcelable {
// 略
}
3、如何与 Handler 关联?
我们知道在消息传机制中 Handler 充当着 "快递员" 的角色,那么他又是如何与 "货物"--Message 发生关系呢?实际上 Message 有一个成员变量 target 他的类型正是 Handler,
- /*package*/
- Runnable callback;
- public int arg1;
- public int arg2;
- public Object obj;
- /*package*/
- Handler target; // 关键点
当我们通过 Handler 去 send 一个 Message 时候最终都会为 target 赋值为 this,即当前的 Handler。
- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this; // 赋值语句
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
- return queue.enqueueMessage(msg, uptimeMillis);
- }
另为如果是通过 Message.Obtain(), 获取的复用 Message 也会为其赋值。
多说一句,Handler.obtainMessage() 调用的就是 Message.Obtain()。
- public final Message obtainMessage(){
- return Message.obtain(this);
- }
总结:
通过一系列的包涵关系,最终 Looper、Handler、Message、MessageQueue 即发生关联,从而形成一个闭合,开启消息循环。
困惑
最近一直在看这方面的知识,但是能力有限,还是有不少困惑,如果有错误,或你理解下面的问题请联系我 {aa0aa}, 愿与君交流学习,谢谢
1、Message 中的 sPool,哪里初始化的?为什么 Message.obtain() 中不会抛异常?
2、ActivityThread 并不是线程,为什么可以创建一个 Looper,Main Thread 什么时候创建?
3、为什么序列化了的对象就可以传递?与 Binder 有关?
4、MessageQueue 对应的是 NativeMessageQueue,具体实现需要学习?
5、Loop.loop(),会退出吗?退出时机是什么?如果会退出,那么主线程同样会退出吗?
来源: http://www.phperz.com/article/17/0315/291576.html