消息机制概述
Handler
利用当前线程的Looper创建内部消息循环系统,主要负责发送和处理消息。另外,也可以通过一个Looper创建一个Handler,这样handler发送的消息就会在Looper所在的线程执行。当我们使用Handler的时候,通过post或者send的一些列方法时,实际上是把一个Message(消息)添加到MessageQueue(消息队列)中去。
MessageQueue
以队列的形式(内部存储结构为单链表)存储和操作消息列表,包含插入和读取消息两个操作,读取是一个无限循环的方法,若消息队列没有消息则一直阻塞,有消息则读取并将其移除
Looper
无限循环地检查MessageQueue是否有新消息,有的话就取出来给Handler处理,否则一直阻塞等待。一般线程默认是没有Looper,若要使用需先创建Looper.prepare(),然后创建Handler,然后Looper.loop()开启消息循环,Looper是运行在Handler所在的线程中的,通过Loop.myLooper()得到当前线程的Looper对象,Handler会使用ThreadLocal来获取当前线程的Looper。若要退出Looper可以采用quit或quitSafely(会清空所有延时消息,处理完消息队列中的非延时消息后再退出)。
Looper类中维护一个消息队列MessageQueue和一个ThreadLocal类型的对象,在Looper的构造函数中对MessageQueue进行了初始化。static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
一个线程只允许存在一个looper对象。而且该对象存储在ThreadLocal里面,若果创建两个Looper则会出现运行时异常,看源码:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
// 这里是关键,如果这个线程已经存在Looper报异常
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 不存在,创建一个Looper设置到sThreadLocal
sThreadLocal.set(new Looper(quitAllowed));
}
主线程的消息循环
在ActivityThread的main方法中通过Looper.prepareMainLooper()创建主线程的Looper及MessageQueue,并通过looper.loop()开启主线程消息循环。
主线程为什么不会因为Looper.loop()循环卡死?
主线程再进入消息循环前,会创建一个Linux管道,可以让主线程再消息队列为空时进入空闲等待状态,当消息队列有消息需要处理时再唤醒主线程。