Android多线程(二)消息处理机制---Handler、Message、Looper源码原理解析
在Android中UI操作不是线程安全的,只有UI线程才能修改UI,所以我们经常开启子线程去处理一些耗时的操作,然后通过Handler发送消息,在UI线程中接送消息并处理UI组件,一个典型的Handler写法如下:
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
......
}
}
Runnable runnable = new Runnable()
{
public void run()
{
......
handler.postDelayed(update_thread, 1000);
......
}
};
或者在子线程中创建Handler:
class ChildThread extends Thread {
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
......
}
};
Looper.loop();
}
}
为什么在子线程使用Handler需要调用Looper.prepare()和Looper.loop(),而主线程中不需要呢?下面,我们就从源码中解析一下Handler的消息处理机制。
Looper工作原理
我们来看一下Looer的构造函数:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在构造函数中创建了一个MessageQueue,正如它的名字,这是一个消息队列,发送的Message都会从消息队列中插入和取出,此外还保存了当前所处的线程mCurrent。注意,Looper的构造函数是private修饰的,也就是说不能通过new来创建一个Looper,只能通过Looper类里面的其他方法来获取,接着看一下prepare()这个方法:
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));
}
原来,当我们调用prepare()这个方法的时候,就会为我们创建一个Looper,而且这个Looper很特殊,是存放在sThreadLocal里面的,sThreadLocal是Looper里面一个很重要的成员变量:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
Threadlocal保证了我们创建的对象只能被当前的线程访问,即每个线程的Looper都是独有的,而且每个线程只能拥有一个Looer对象,否者就会抛出异常”Only one Looper may be created per thread”。看到这里,也就是解释了为什么在线程中使用Handler时需要调用Looper.prepare(),那为什么在UI线程中不需要调用Looper.prepare()呢,其实在Looper中还有一个方法:
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
从注释中可知,当我们创建一个应用的时候,系统就已经为创建了一个main looper了,因此当我们使用Handler时就默认使用了这个main looper。Looper.prepare()完成之后接下来就是Looper.loop(),只有调用loop()之后,消息循环系统才真正地运行起来:
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;
}
try {
msg.target.dispatchMessage(msg);
} finally {
......
}
......
msg.recycleUnchecked();
}
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
从以上代码看到,loop()方法中通过myLooper()获取了在prepare()中创建的Looper对象,接下来就是一个死循环,只有MessageQueue的next为null即消息为空时才能跳出循环。如果消息不为空,接着就调用msg.target.dispatchMessage(msg)去处理消息,msg.target就是我们创建的Handler对象,消息处理流程在这切换到了Handler中,这样就把Looper、Handler、Message、MessageQueue联系起来了。
Handler工作原理
Handler主要的工作就是发送和接收消息,发送消息是通过一系列的postXXX和sendXXX方法实现的,以上一系列方法最终调用的是sendMessageAtTime()这个方法:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
sendMessageAtTime()负责将Message压如MessageQueue中,然后MessageQueue的next()取出Message交给Handler的dispatchMessage()去处理:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
如果Message的callback不为空的情况下就通过handleCallback(msg)来处理消息,这里的callback其实是一个Runnable对象,也就是通过post(Runnable r)传入的;如果msg.callback为空,则去检查mCallback是否为空,这个mCallback是Handler内部的一个接口:
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
如果我们创建Handler的时候使用的是Handler(Callback callback)的话,就需要重写Callback接口的handleMessage(Message msg)方法,这样消息的处理就由Callback处理,如果没有传入自己的Callback,最后就会调用Handler自己的handleMessage(Message msg)来处理消息,这也是我们最常用的方式。
总结
这样,Handler处理消息的流程就分析完了,我们来总结一下:
1、首先我们通过Looper.prepare()创建了一个Looper对象,如果是UI线程的话,系统则会自动为我们通过prepareMainLooper()创建Looper对象,然后在Looper中创建了一个消息队列MessageQueue,每个线程都只对应这个唯一的Looper,每隔Looper又对应着唯一一个MessageQueue;
2、Looper.loop()是一个死循环,不断地从MessageQueue中取出Message交给Handler的 dispatchMessage处理;
3、Handler通过创建Handler时采用的构造函数不一样,采用不同的方法来处理消息。
推荐阅读
-
android的消息处理机制(图文+源码分析)—Looper/Handler/Message
-
android的消息处理机制(图文+源码分析)—Looper/Handler/Message
-
Android消息通信机制Handler详解,Handler,Looper,MessageQueue,源码解析,讲解这几个类怎么配合工作的
-
Android消息处理机制(Handler、Looper、MessageQueue与Message)
-
Android异步消息处理机制 深入理解Looper、Handler、Message的关系
-
简述android线程间消息处理机制(Looper、Handler和Message)
-
Android消息机制三剑客之Handler、Looper、Message源码分析(一)
-
Android消息机制原理,仿写Handler Looper源码解析跨线程通信原理--之仿写模拟Handler(四)
-
Android多线程(二)消息处理机制---Handler、Message、Looper源码原理解析
-
Android消息机制系列(1)——Handler Looper Message源码解析