1.簡要
有些初級開發者總是認爲Handler是用來更新UI的。這從其主要使用場景上講,是沒有問題的。但是要想更好的去了解Handler及其背後的運行機制,這個認識往往會導致對Handler理解的不夠深刻,可謂是一葉障目,不見泰山。(PS:我在面試過程中,經常會考察面試者對於Handler的認識)
片面認識—— Handler是用來更新UI的。
2. 面試迷茫點
No Looper; Looper.prepare() wasn’t called on this thread.
Only one Looper may be created per thread
上面這兩個異常,有些開發者可能在實際開發工作中都沒有遇到過。究其原因,沒有在子線程中去創建過Handler。
這也是有很大一部分面試者,談到Handler的運行機制,用法及注意事項時,能做到侃侃而談。下面列出幾種常見場景:
- 當談起多線程通信時,有一些面試者不知所云,但是說Handler,立刻就精神煥發。
- 涉及到HandlerThread的存在意義,有些茫然無措。
- 涉及到Handler,Thread,Looper,MessageQueue之間的對應關係時,有些說不清楚。
個人認爲,這都是對於Handler的片面認識導致的。
3. Thread 和 Looper的婚姻關係
廢話一句,我還是希望大家能仔細看一下上面的文字…
No Looper; Looper.prepare() wasn’t called on this thread. 不存在Looper——在該線程中沒有調用Looper.prepare()方法。
Only one Looper may be created per thread 一個線程只能創建一個Looper。
從上面的錯誤提示中,我們可以得出一個結論:線程和Looper是1:1對應的關係
我們今天這篇文章主要探討的是:如何保持這種正常的婚姻關係?
在Looper類中,你會看到:
ThreadLocal成員變量
// sThreadLocal.get() will return null unless you've called prepare().
// 若不調用prepare()方法則返回null
@UnsupportedAppUsage(只支持APP使用)
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
prepare()方法
// 清楚地看到該變量的set()/get()
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 注意這裏:新建Looper,我們看看Looper構造函數幹了些什麼
sThreadLocal.set(new Looper(quitAllowed));
}
Looper方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
是誰在努力維持着這段美好的婚姻(Looper 和 Thread )呢?
Oop, ThreadLocal.
3.淺識ThreadLocal
1. set()方法
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. 給當前線程設置一個指定的值。
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
key-value形式:當前線程爲key,value就是我們傳過來的值。這唯一性就保持住了。So easy…
看見這個ThreadLocalMap,每個人都會猜測,它難道是一個HashMap 或者HashTable,抑或是 CocurrentHashMap。走過去看一下吧。
/*ThreadLocalMap is a customized hash map suitable only for
* maintaining thread local values
* /
static class ThreadLocalMap {
}
ThreadLocalMap是一個只適用於維護thread local 的自定義鍵值對。
4. 總結:
- Looper 和Thread 是 1V1的關係,其由ThreadLocal來維持關係;
- ThreadLocal 內部是由ThreadLocalMap來存儲的,key 就是當前線程。
歡迎繼續收看 :Handler的前世今生2——Looper