要分析Handler的原理,首先需要了解Message和Looper,所以我们先来分析一下Message和Looper的源码。
Message
首先根据注释来看一下Message的定义:
/**
*
* Defines a message containing a description and arbitrary data object that can be
* sent to a {@link Handler}. This object contains two extra int fields and an
* extra object field that allow you to not do allocations in many cases.
*
* <p class="note">While the constructor of Message is public, the best way to get
* one of these is to call {@link #obtain Message.obtain()} or one of the
* {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
* them from a pool of recycled objects.</p>
*/
定义一个包含描述和任意数据对象的对象,将这个对象发送给Handler处理。这个对象包含两个额外的int字段和一个额外的object字段,但在很多情况下,这些字段并要求你必须给他们赋值。同时提醒我们,虽然Message的构造函数是public的,但是最好是调用Message.obtain()方法,这个方法会从回收池里获取Message对象。obtain方法是怎么回收利用Message的呢,从以下方法中分析:
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
1、这里的sPoolSync是一个Object实例,sPool是一个Message对象,如果sPool不为null的话,会将sPool赋值给一个新的Message对象,并将m.next赋值给sPool,m.next也是一个Message,同时,最终返回m。由于取出了一个Message,所以sPoolSize–,如果有另外线程调用Message.obtain,则会直接创建一个新的Message返回;
/**
* Same as {@link #obtain()}, but copies the values of an existing
* message (including its target) into the new one.
* @param orig Original message to copy.
* @return A Message object from the global pool.
*/
public static Message obtain(Message orig) {
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
m.sendingUid = orig.sendingUid;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
}
2、根据注释可以看出,该方法与obtain()方法一样,不同之处在于,这个方法的参数是一个已存在的Message,它首先调用botain()方法,获取一个已存在的Message,然后将参数Message的值赋值给m对应的属性,最终返回m。其他几个obtain方法都是多了一些传参,对m的某些值做了修改,就不多做赘述了,Message内部还有一些其他方法,但是一般在使用Handler时不会使用,所以就不予以描述了。
Looper
Looper对与Handler来说,是一个很重要的概念,不了解Looper就不能真正弄懂Handler的机制,所以,先来了解一下Looper,先看一下官方对与Looper的定义。
/**
* Class used to run a message loop for a thread. Threads by default do
* not have a message loop associated with them; to create one, call
* {
@link #prepare} in the thread that is to run the loop, and then
* {
@link #loop} to have it process messages until the loop is stopped.
*
* <p>Most interaction with a message loop is through the
* {
@link Handler} class.
*
* <p>This is a typical example of the implementation of a Looper thread,
* using the separation of {
@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }</pre>
*/
官方对与Looper的定义为,针对一个线程运行的消息循环。线程默认是没有消息循环相关联的,要创建一个消息循环,就要调用Looper的prepare方法,然后调用Looper的loop方法来循环处理消息,直到循环停止。下边官方也说明大多数与消息循环的交互是通过Handler来实现的。最后官方给出了一个创造包含消息循环的线程的例子。下边看一下Looper具体的代码:
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
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.loop()方法之前调用,最后要调用quit()方法退出循环。这两个方法
唯一的不同就是多了一个boolean类型的参数。无参的prepare方法调用了有参的prepare方法,并默认参数为true。从有参的prepare方法中可以看到,有个sThreadLocal对象,并调用了该对象的get方法,我们看下它的get方法最终会返回什么:
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
首先,该方法会获取当前线程,并获取当前线程的ThreadLocalMap,ThreadLocal是一个定制的HashMap,是为了维护线程本地值而诞生的,如果当前线程的ThreadlocalMap不为null,则根据key,获取Entry,将Entry.value返回。如果map为null,则调用setInitialValue方法,再看这个方法是用来干什么的:
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);