一、什么是消息循环
消息循环概述:Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环,通过消息循环可实现线程间通信。在Android线程内,可以通过消息循环的机制以队列的方式实现消息的发送,处理等工作
作用:线程间通信
涉及到的核心类:
Message:消息的实体的封装
Handler:消息的发送和处理
Looper:消息循环的核心,管理消息队列,实现与当前线程绑定
MessageQueue:消息队列
二、消息循环的过程
消息循环可以分为两部分来讲
- 给线程开启消息循环
class WorkThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// 处理收到的消息
}
};
Looper.loop();
}
}
WorkThread myWorkThread = new MyThread2();
myWorkThread.start();
- 创建Message,并发送Message,处理Message
Message msg = Message.obtain();
msg.what = what;
msg.obj = strMsg;
myWorkThread.mHandler.sendMessage(msg);
二、消息循环的原理
开启线程的消息循环
如上代码,就开始了WorkThread线程的消息循环,在主线程或者其他子线程,就可以通过WorkThread.mHandler向WorkThread线程发送Message,并且由handleMessage最终处理Message
我们按照代码的步骤来看主要就是做了3个步骤
- Looper.prepare()
- new Handler()
- Looper.loop()
1. Looper.prepare()
static final ThreadLocal sThreadLocal = new ThreadLocal();
final MessageQueue mQueue;
final Thread mThread;
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
//初始化了MessageQueue
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
代码很简单,可以看出prepare()就是
- new了一个Looper对象,同时初始化了MessageQueue。
- 把该Looper对象放入了创建它的当前线程的ThreadLocal里,建立Looper与创建它的线程的关联(ThreadLocal不理解的同学,可以先查看一些ThreadLocal的资料)。可以理解为Looper成为了创建它的当前线程的一个本地变量
放到前面代码里,就是为WorkThread线程创建了一个本地变量Looper,可以在WorkThread线程中用Looper.myLooper()来获取该Looper对象
2. 创建Handler
我们来看下Handler的构造函数
public Handler() {
this(null, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//获取创建线程的Looper
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;
mCallback = callback;
mAsynchronous = async;
}
由上面代码可以看出
new Handler()的时候必须先给handler指定一个Looper(在主线程中不需要指定,因为主线程的消息循环在程序启动时就已经开启了),否则会抛出异常,即Handler使依附于Looper的
3. Looper.loop()
public static void loop() {
......//省略
for (;;) {
Message msg = queue.next(); //可能阻塞 MessageQueue中取出msg
......//省略
msg.target.dispatchMessage(msg);//分发msg
......//省略
msg.recycleUnchecked();//回收msg
}
}
代码比较长,我们挑核心来看,其实主要就是做了三件事
- 开启了一个死循环for(;;)
- 从MessageQueue中取出Message
- 分发Message
- 回收Message
由于这是一个死循环,这个循环会不停的调用queue.next(),从MessageQueue中取出Message来处理,然后调用dispatchMessage来分发Message,最后回收msg
这样一个线程的消息循环就建立了,其他线程就可以通过该线程的handler与该线程进行通信
创建Message,并发送Message,处理Message
1. 创建Message
我们在Looper.loop()中知道,Message在发送后会被回收,那么我们一起看下Message的构造函数和回收函数
/** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
*/
public Message() {
}
private static final Object sPoolSync = new Object();
private static Message sPool;//单链表结构的头部引用
Message next;
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;//复用Message
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
//sPool为null 则新建
return new Message();
}
void recycleUnchecked() {
//重置了Message的参数
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
//将Message以单链表的方式存储
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
//sPool指向单链表的头部
sPool = this;
sPoolSize++;
}
}
}
由代码可以看出Message构造函数虽然是public的,但是官方建议我们用obtain()来或者Message。由obtain()和recycleUnchecked()代码可以看出Message采用一个单链表结构的对象池,来复用Message对象。
2. 消息发送handler.sendMessage和处理
看源码可知,handler.sendMessage的几个重载的方法,最终是调用了sendMessageAtTime方法,而sendMessageAtTime又调用了enqueueMessage方法,而enqueueMessage方法最终是调用了MessageQueue的enqueueMessage方法,把Message加入到了消息队列中
伪代码调用逻辑如下
handler.sendMessage(Message msg){
sendMessageAtTime(Message msg, long uptimeMillis){
enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis){
MessageQueue.enqueueMessage(msg, uptimeMillis)
}
}
}
然后从Looper.loop()中可以看到,Message在被发送到MessageQueue中后,loop()中开启的死循环是调用了MessageQueue.next()方法取出了Message,并调用msg.target.dispatchMessage(msg)方法来分发msg,而msg.target就是handler,那么看下handler的dispatchMessage方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
public interface Callback {
public boolean handleMessage(Message msg);
}
private static void handleCallback(Message message) {
message.callback.run();
}
可以看出dispatchMessage有3中逻辑
- 调用了message.callback.run(),来处理message
runOnUiThread(),handler.post(Runnable r)就是这样处理的 - handler的Callback接口方式来处理消息,在创建handler的时候可以指定一个mCallback来处理消息
- handler.handleMessage来最终处理消息
这样从消息循环的开启,到消息的发送,处理就完成了
总结
- Looper是和当前线程关联的,Looper.prepare()建立与调用它的当前线程的关联,Looper.loop()开启当前线程消息循环
- handler是和Looper关联的,创建handler的时候必须指定其Looper,而主线程由于在程序开启时就开启了它的消息循环,所以只有在主线程创建handler的时候,不需要指定其Looper
- 创建Message,用Message.obtain(),可以复用Message,不要直接new。
- 在子线程中开启的消息循环,可调用Looper.myLooper().quit(),来退出消息循环,主线程的消息循环不可退出