Handler对象通过线程的MessageQueue,允许你发送或者处理一个Message对象或者一个Runnable对象。 每一个Handler对象,都与一个单独的线程和线程的MessageQueue相关联。当你创建一个新的Handler对象, 这个Handler对象便与创建这个handler对象的线程和线程的MessageQueue相绑定。从这时起,这个handler对象 将传入message对象或者runnable对象到MessageQueue中或者从MessageQueue中提取Message对象,并进行相应处理。
Handler有两个主要的作用: (1)安排message或者runnable对象在未来的某个时间点执行; (2)在其他的线程中执行相关逻辑。
在应用进程被创建的时候,MainThread会创建一个MessageQueue,这个MessageQueue将会用于高等级的应用对象 (例如:activitys、broadcast reveivers等)和任意一个它创建的windows。也可以创建子线程,与主线程进行交流。
1.主要代码
与Handler机制相关的有几个类 Looper、MessageQueue、Message和ThreadLocal。
ThreadLocal
这个类提供线程本地变量,即为不同的线程变量提供不同的副本。通过get和set方法。ThreadLocal一般为类的私有静态变量,用于关联线程的state。
例如,下面这个类,用于为每一个线程创建唯一id。线程的id在第一次调用ThreadId.get()方法后被分配,在之后不会变化
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadId {
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId =
new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
return threadId.get();
}
}
每一个线程都持有这个线程的ThreadLocal的一个copy的明确引用。直到这个线程不在存活或者Threadlocal单例不存在。
1.ThreadLocalMap类
与ThreadLocal类相关的还有一个非常重要的类 ThreadLocalMap。真正的数据存储是由ThreadLocalMap类完成的。在Thread类中包含一个ThreadLocalMap变量。不过这个变量是可见性是默认的,只能包内访问到。
Thread.class
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocalMap类是一个静态内部类。自定义一个静态类用于存储数据的条目。
//继承WeakReference 弱引用。已ThreadLocal对象为key,Object为value。组成键值对。
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
- 变量
// 初始化的容量必须是2的倍数
private static final int INITIAL_CAPACITY = 16;
//存储数据数组,在必要是可以重新计算数组长度。数组长度必须是2的倍数。
private Entry[] table;
//存储数据table容量。
private int size = 0;
//判断是否需要重新计算数组容量的标志 默认值0
private int threshold; // Default to 0
- 构造方法
//创建一个新map,初始值为firstKey和firstValue。只有在至少一个entry放入的时候才会创建。
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];//创建存储数据数组,大小默认值为16。
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);//计算存储位置。具体算法没看懂。
table[i] = new Entry(firstKey, firstValue);//存入数据
size = 1;//修改size
setThreshold(INITIAL_CAPACITY);//修改shreshold变量 为INITIAL_CAPACITY * 2 / 3;
}
//另外一个构造方法,参数为ThreadMap,即copy创建一个新的ThreadMap。私有方法
private ThreadLocalMap(ThreadLocalMap parentMap);
- get(hreadLocal<?> key)
/**
*通过ThreadLocal key获取value。因为存储Entry是个弱引用和存储数据位置散列可能有碰撞。
*所以会出现找不到的问题。则交与getEntryAfterMiss()方法来处理。
*/
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);//计算存储位置
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);//未找到则交于getEntryAfterMiss()方法处理。
}
//处理无法直接从key获取value的情况。
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
while (e != null) {
ThreadLocal<?> k = e.get();
if (k == key)
return e; //正常返回
if (k == null)
expungeStaleEntry(i);//从Entry获取的key,key已经不存在了。则抹去对这个entry的存储。
else
i = nextIndex(i, len);//key存在,但是已经不是之前值了。则重新计算位置并存储entry。
e = tab[i];
}
return null;
}
- set(ThreadLocal<?> key, Object value)
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
//遍历数组,判断数组中是否已经存过相同key数据。
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) { // key与数组中entry的key相等。则替换value。
e.value = value;
return;
}
if (k == null) { //数组entry key为null。则替换这个entry
replaceStaleEntry(key, value, i);
return;
}
}
//数组中不存在这个key 也不存在key为null的情况。则新建entry,并加入数组。
tab[i] = new Entry(key, value);
int sz = ++size;
//cleanSomeSlots()方法查找整个数组,发现entry为null或者entry.get()为null。则
//删除掉这个entry。如果有删除过entry则返回true。否则返回false。
//假如没有删除过entry 并且增加后的数组长度 >=threshold变量。则重新计算数组大小。
//上面也说过 threshold 变量为数组长度的三分之二。
//rehash将会将数组容量扩大一倍。
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
2.主要方法
- initialValue()
//主要用于创建每个线程的ThreadLocal值的初始化。上面线程Id的例子中重写了这个方法。
//已实现创建ThreadLocal便初始化Id的功能。这个方法会在Thread第一次调用ThreadLocal变量的get()方法时调用。
protected T initialValue() {
return null;
}
2.get()
public T get() {
//获得当前线程
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);//获取thread对应的ThreadLocalMap成员变量。
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //通过key获取value。
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();//如果未找到value则 初始
}
//初始化线程ThreadLocalMap变量
private T setInitialValue() {
T value = initialValue(); //获取初始化值,上面的例子中用到这个方法。用于初始化线程Id。
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value); //线程已存在ThreadLocalMap变量 则加入新初始化的entry。
else
createMap(t, value); //线程未初始化ThreadLocalMap变量则,初始化并加入新entry
return value;
}
3.set(T value)
//线程已存在ThreadLocalMap变量,则加入entry。
//线程未初始化ThreadLocalMap变量则,初始化并加入entry。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
4.如何计算存储位置。即如何计算entry在ThreadLocalMap中数组table的下标。
计算公式为:有ThreadLocal的nextHashCode()方法,即从0开始每次调用增加 HASH_INCREMENT = 0x61c88647。即0x61c88647的倍数。
//firstKey.threadLocalHashCode = nextHashCode();
//INITIAL_CAPACITY为数组长度。 默认为16.必须为2的倍数。
//因为INITIAL_CAPACITY为2的倍数。所以公式的表示为:取firstKey.threadLocalHashCode的低几位。
//搜了下资料 这个数的选取与斐波那契散列有关。使用这种方式取的值分布很均匀。XD.原因不懂。
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
MessageQueue
用于Looper使用的缓存message列表的初级类,并不是直接通过MessageQueue添加,而是通过与Handler相关联的 Looper。你可以在当前线程中使用Looper.myQueue()方法获取这个对象。
主要方法
1.next()
// 取出message的方法。
Message next() {
、、、
for (;;) {
、、、
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {//msg.target即为发出这个message的Handler
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
//当前时间戳小于msg.when,即下一个message还没有准备好,则设置超市启动时间。
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 下一个message已经到时间。则将message从链表中取出并返回这个message。
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
、、、
}
}
2.enqueueMessage(Message msg, long when)
// 插入一个message。
boolean enqueueMessage(Message msg, long when) {
、、、
synchronized (this) {
、、、
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
//队列中没有message 或者插入message.when为0 或者小于当前对列头部message时间戳
//则将插入message 插入到队列头部。
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//判断message的when并插入到队列中间。
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
Looper
用于Threand中的消息循环。线程默认是没有这个循环的。使用prepare()方法创建。调用loop() 方法,开启循环。 下面例子为创建与Handler交互的Thread。
//eg:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
//在这处理传入message
}
};
Looper.loop();
}
}
主要变量
//sThreadLocal.get()在调用prepare()方法之前,返回null。
//Looper类中存在静态的TheadLocal,并且拥有对象中拥有MessageQueue对象。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper;
final MessageQueue mQueue;
final Thread mThread;
主要方法
1.loop()
//循环县城中的MessageQueue。务必在退出的时候调用quit方法。
//把看不懂的代码删掉之后,显而易见,及从MessageQueue中取message。并调用
//message.target即发送这个message的handler对象的dispatchMessage()方法。
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) {
return;
}
、、、
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
、、、
msg.recycleUnchecked();
}
}
2.prepare(boolean quitAllowed)
//新建一个Looper对象存入到这个当前线程的ThreadLocalMap变量中。
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));
}
Handler
前面的ThreadLocal、MessageQueue、Lopper已经清楚后,Handler的代码就很清晰了。
主要方法
1.dispatchMessage(Message msg)
//这个方法在Looper的loop()方法中调用。
//可以从这个方法中 看出Handler的回调逻辑和顺序。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
2.enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
//Handler 所有的发送消息的方法,最后都调用这个方法。
//该方法只是调用了Looper对象中的MessageQueue对象的enqueueMessage();方法。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
总结
Handler主要是使用ThreadLocal的在不同线程中保存不同的副本的机制来实现。 在创建Handler对象的时候调用Looper.prepare()方法。为当前线程添加一个ThreadLocal对象用于 保存一个Looper对象。而Looper对象中拥有一个MessageQueue对象。这样就形成了每一个线程对象中都保存一个 Looper对象和MessageQueue对象的结果。因此当Handler发送信息时,即向当前线程MessageQueue中加入一个message。 而当前线程的Looper则从MessageQueue中提取message。并执行Handler发送message时设置的回调。因为Looper在各个 线程中存在不同的副本。所以实现了跨线程通信。