Android 异步消息处理机制的出现主要是为了解决android系统中不允许在子线程中不能更新UI,而只能必须在主线程(即UI线程)中进行更新的问题;
下面详细介绍下android异步消息处理机制中的三元素(Handler、Message、Looper);
我们首先来分析下Handler:
每个Handler实例都与单个线程(Thread)以及该线程的消息队列(MessageQueue)相关联;当您创建一个新的Handler实例时,该Handler实例将会绑定到创建该实例的线程(Thread)及该线程的消息队列(MessageQueue);官方的原话是: Each Handler
instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it.
上面的原因是:Handler实例的创建依赖于Looper实例;而一个线程(Thread)中最多只能创建一个Looper实例,因此Handler实例单个线程(Thread)以及该线程的消息队列(MessageQueue)相关联;部分源代码如下:
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());
}
}
mLooper = Looper.myLooper();
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;
}
Handler实例可以通过调用sendMessage()系列方法以及post()系列方法来发送消息;通过调用removedCallbacks()系列方法来实现清除消息;
我们继续分析Message:
消息(Message)是线程之间进行通信的媒介;Message中有个很重要的成员target,它的数据类型是Handler,说到这里,恐怕大家已经猜到了这个target的作用了吧。没错,它的作用就是:将Message 实例与Handler实例进行绑定;从而实现Message与Handler的一一对应;
补充:官方建议消息的获取可以通过调用Message.obtain()方法来实现;
我们最后再来分析Looper:
之所以把Looper放到最后来分析,那是因为我认为它在异步消息处理机制中的分量属于最重的;
Looper类的作用,官方的原话是:Class used to run a message loop for a thread. 中文翻译就是:用于为线程运行消息循环的类。很准确,Looper类的作用就是为线程运行消息循环的类;
那异步消息处理机制中是Looper实例是如何被创建以及它是如何运行消息循环的呢?下面我们一一来分析;
Looper实例的创建是在Looper类的静态方法prepare()中被创建的;同时android 系统为了保证一个线程只能创建一个Looper实例,使用的jdk中标准的ThreadLocal类;通过调用ThreadLocal实例的set()、get()来实现;官方源代码为:
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));
}
那线程中消息循环是如何运行的呢?
消息循环是通过调用Looper类的静态方法loop()来实现的;loop方法中实现了一个死循环;部分源代码如下:
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycle();
}
代码中有几点这里注意下;第一点就是消息的获取 Message msg = queue.next();这个是同步的,可能会出现阻塞;第二点就是Message实例的判空,这里实现非常巧妙,巧妙之处就是外界可以通过调用Looper的静态退出方法quit()来实现循环结束;原理其实就是销毁消息队列;
补充:Looper中有个非常重要的MessageQueue类型的 final 成员 mQueue;