1.消息机制的简介
在Android中使用消息机制,我们首先想到的就是Handler。Handler是Android消息机制的上层接口。通过它可以轻松地将一个任务切换到Handler所在的线程中去执行。通常情况下,Handler的使用场景就是更新UI。
Handler的运行是需要底层的MessageQueue和Looper的支撑。在本消息机制中,主要有如下几个部分:
1、Message
Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于不同的线程之间交换数据。可以使用what字段、arg1、arg2携带一些整型数据,使用obj字段携带一个Object对象。
2、Handler
Handler就是处理者的意思,它主要用于发送和处理消息,发送消息一般在主线程构造一个Handler,在其他线程调用Handler的sendMessage()方法,此时主线程的MessageQueue中会插入一条message,然后被Looper使用。Handler在创建时会通过ThreadLocal来获取当前线程的Looper来构造消息循环系统。
3、MessageQueue
MessageQueue是消息队列,每个线程中只会有一个MessageQueue对象,单链表维护,在插入和删除上有优势。主要用于存放所有通过Handler发送的消息,这部分消息会一直存在于消息队列中,等待被处理。在其next()中会无限循环,不断判断是否有消息,有就返回这条消息并移除。
4、Looper
Looper创建时会创建一个MessageQueue,调用loop()方法时消息循环开始(死循环),会不断调用MessageQueue的next()方法,当有消息就传递到Handler的handlerMessage()方法中处理,否则阻塞在messageQueue的next()中。当Looper的quit()被调用的时候会调用messageQueue的quit(),此时next()会返回null,然后loop()方法也跟着退出。每个线程中也只会有一个Looper对象。
创建Handler后,重写hangleMessage()方法,然后通过Handler的post()方法将一个Runnable投递到Handler内部的Looper中去处理,也可以通过Handler的send()方法,发送一个message,该消息同样会在Looper中处理。send()方法的工作过程:当send()方法被调用时,它会调用MessageQueue的enqueueMessage()方法,该方法将这个消息放入到消息队列中(post()方法也是通过send()方法实现)。而Looper则会尝试在MessageQueue中取出待处理的消息,然后Runnable或者handler的handleMessage()方法就会被调用。由于Looper是运行在创建Handler所在的线程中的,这样Handler中的业务逻辑就被切换到创建Handler所在的线程中去执行了。
2.Android的消息机制分析
1.Looper
要想使用消息机制,首先要创建一个Looper。
初始化Looper
无参情况下,默认调用prepare(true);表示的是这个Looper可以退出,而对于false的情况则表示当前Looper不可以退出。不能重复创建Looper,只能创建一个。创建Looper,并保存在ThreadLocal。其中ThreadLocal是线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。
开启Looper
public static void loop() {
final Looper me = myLooper(); //获取TLS存储的Looper对象
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //获取Looper对象中的消息队列
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) { //进入loop的主循环方法
Message msg = queue.next(); //可能会阻塞,因为next()方法可能会无限循环
if (msg == null) { //消息为空,则退出循环
return;
}
Printer logging = me.mLogging; //默认为null,可通过setMessageLogging()方法来指定输出,用于debug功能
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg); //获取msg的目标Handler,然后用于分发Message
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
}
msg.recycleUnchecked();
}
}
当next()取出下一条消息时,队列中已经没有消息时,next()会无限循环,产生阻塞。等待MessageQueue中加入消息,然后重新唤醒。
主线程中不需要自己创建Looper,这是由于在程序启动的时候,系统已经帮我们自动调用了Looper.prepare()方法。
2.Handler
创建Handler
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
.................................
//必须先执行Looper.prepare(),才能获取Looper对象,否则为null.
mLooper = Looper.myLooper(); //从当前线程的TLS中获取Looper对象
if (mLooper == null) {
throw new RuntimeException("");
}
mQueue = mLooper.mQueue; //消息队列,来自Looper对象
mCallback = callback; //回调方法
mAsynchronous = async; //设置消息是否为异步处理方式
}
对于Handler的无参构造方法,默认采用当前线程TLS中的Looper对象,并且callback回调方法为null,且消息为同步处理方式。只要执行的Looper.prepare()方法,那么便可以获取有效的Looper对象。
3.发送消息
在子线程中通过Handler的post()方式或send()方式发送消息,最终都是调用了sendMessageAtTime()方法。
4.获取消息
当发送了消息后,在MessageQueue维护了消息队列,然后在Looper中通过loop()方法,不断地获取消息。其中最重要的是调用了queue.next()方法,通过该方法来提取下一条信息。
5.分发消息
在loop()方法中,获取到下一条消息后,执行msg.target.dispatchMessage(msg),来分发消息到目标Handler对象。
分发消息流程:
当Message的msg.callback不为空时,则回调方法msg.callback.run();
当Handler的mCallback不为空时,则回调方法mCallback.handleMessage(msg);
最后调用Handler自身的回调方法handleMessage(),该方法默认为空,Handler子类通过覆写该方法来完成具体的逻辑。