Android在Java标准线程模型的基础上,提供了消息驱动机制,用于多线程之间的通信。基于消息驱动机制的线程通信模型称为称为线程消息通信。在标准线程模型中,可以首先在线程内部创建一个消息队列,然后让线程进入一个无限循环中,在这个无限循环中,线程会不断检查消息队列中是否有消息。如果需要线程执行某个任务,便向线程的消息队列中发送对应的该任务的消息,线程在无限循环中检查到消息队列中有消息到来,便会获取该消息,进而执行该消息对应的处理流程。如果线程的消息队列中没有消息,线程便进入等待状态,等待消息的到来。这样便可以通过消息控制线程的执行,因此也称为消息驱动机制。
消息驱动机制涉及的4个概念:消息、消息队列、消息循环、消息处理器。
消息用于表示一个可执行任务,通常在消息内部会封装消息的标志、消息的执行时间以及消息数据。消息创建完毕后,通过消息处理器将其发送到象策划过的消息队列中,消息队列维护当前可执行消息的列表。当前线程进入消息循环中遍历消息队列获取消息,然后根据消息标志通知消息处理器执行对应的处理函数。
Looper线程:
Android基于Java标准线程模型开发了Looper 线程,用于实现消息驱动机制。Looper 线程与标准线程的区别在于:Looper 线程的run 方法执行后并不会立即退出,而是进入一个loop 消息循环中等待消息的到来,然后根据消息类型分别作出不同的处理。这样,后台中只需要运行单一线程,当需要定时或者不定时执行不同任务时,分别发送不同的消息给Looper 线程去处理,这样就避免了频繁创建/销毁线程所带来的开销。
Looper线程首先是一个Thread,由Java 标准线程演化而来。将一个普通线程变成Looper 线程只需要以下代码:
class LooperThread extends Thread{//继承自Thread
public Handler mHandler;//需要一个handler 对象发送和处理消息
public void run(){
Looper.prepare();//Looper 线程准备阶段
mHandler = new Handler(){//初始化消息处理器
public void handlerMessage(Message message){
//处理消息的逻辑
}
};
Looper.loop();//Looper线程循环阶段
}
}
通过上面的代码我们得出在Looper线程启动后进入run 方法后执行了一下三步操作:
- 调用Looper.prepare 方法进入Looper 线程准备阶段。
- 创建Handler 对象用于实现消息处理器,消息处理器负责发送和处理消息。
- 调用Looper.loop 方法进入Looper 线程循环阶段。
通过以上三步,Looper 线程提供了消息驱动机制的消息队列、消息循环和消息处理器。
第一阶段:Looper 线程准备阶段:
public class Looper {
//定义一个线程局部对象存储Looper对象
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper;
final MessageQueue mQueue;
final Thread mThread;
volatile boolean mRun;
private Printer mLogging;
//将当前线程初始化为一个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 pre thread");
}
/*
* 创建Looper 对象并存入SThreadLocal,这样每个调用prepare
* 方法的线程将创建本线程唯一的Looper 对象
*/
sThreadLocal.set(new Looper(quitAllowed));
}
public static Looper myLooper(){//用于返回当前线程的Looper 对象
return sThreadLocal.get();
}
}
从以上源代码可以看出:在对应的线程中只能调用一次prepare 方法,如果多次调用prepare 方法会导致线程异常退出,综上所述prepare 方法创建了一个线程独立且唯一的Looper 对象,如果要访问这个Looper 对象,只需要调用myLooper 方法。
第二阶段:消息处理器Handler
Handler 是Looper 线程的消息处理器,创建并初始化Handler 是Looper 线程运行过程中的关键步骤之一。Looper 线程是由消息驱动 的,Message便是消息的载体,Handler 承担了消息驱动机制的发送消息和处理消息两部分工作,创建Handler 对象的过程并没有特别之处,就是将之前在本线程中创建的Looper 和 MessageQueue 关联到其成员变量之中,这样Looper 、MessageQueue和Handler就连在一起了。Handler 的成员变量mMessenger 用于跨进程发送消息。
Message 实现了Parcelable 接口,这相当于Java的序列化和反序列化机制。可序列化保证Message 对象可以通过Intent 或者 Binder 远程传递。
- what 成员变量表示消息的消息码,用于唯一标识一条消息。
- when 成员变量表示消息在什么时间执行,取值为0表示立即执行。Message在消息队列中是按照消息执行时间 when 排列的。
- next 成员变量用于表示下一条消息,因此Message 本身实现了一个单向链表结构。
- sPool 用于表示消息池,每次调用obtain 方法相当于取出消息池头部的消息。
第三阶段:Looper 线程循环阶段
Looper 线程完成准备和初始化Handler 的工作后,便进入Loop 方法。
public static void loop(){
final Looper me = myLooper();//获取线程局部变量中存储的Looper 对象
if (me == null) {//调用loop 方法必须首先调用prepare 方法。
throw new RuntimeException("No looper:Looper.prepare() was't called on this thread");
}
final MessageQueue queue = me.mQueue;//获取Looper 中存储的 MessageQueue
Binder.clearCallingIdentity();//在IPCThreadState 中记录当前线程所属的PID和UID
final long ident = Binder.clearCallingIdentity();
for(;;){//在无限循环中轮询MessageQueue
Message msg = queue.next();//可能阻塞
if(msg == null){
//无消息时,消息队列退出
return;
}
Printer logging = me.mLogging;
msg.target.dispatchMessage(msg);//将读取的消息发送到消息处理器
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
}
<strong>msg.recycle();//将处理过的消息重新初始化并放入消息池中
}
}
Loop方法的主要工作可以分为
四部分:
- 调用Binder.clearCallingIdentity方法记录并获取当前线程身份信息
- 调用MessageQueue.next 方法循环监听获取消息
- 调用Message 中的target 成员变量的dispatchMessage ,分发消息到处理器.
- 调用Message 的recycle() 方法,回收消息并更新消息。回收消息的过程只是将消息的成员变量清空(置为0),并没有回收消息对象本身,因此消息被回收后,不能直接操作该消息。