在Android系統(tǒng)中,Handler機(jī)制應(yīng)用較廣,尤其是在App層面,基本每個(gè)App都會用到。使用的場景主要是向主線程發(fā)送事件,更新UI。但大家真的了解Handler機(jī)制嗎?看一下面的幾個(gè)問題是否可以回答:
a.Handler是如何實(shí)現(xiàn)多個(gè)線程之前事件傳遞的?
b.Handler、Message、MessageQueue、Looper相互之間的數(shù)量比是多少,都是1:1嗎?
c.每個(gè)變量運(yùn)行的線程是那個(gè)?
d.ThreadLocal是怎么回事,在Handler機(jī)制中起什么作用?
能準(zhǔn)確回答上述問題,說明對Handler機(jī)制的理解已相當(dāng)?shù)轿涣恕?/p>
一、下面論述一下Handler機(jī)制各類的實(shí)現(xiàn)原理,從而揭露內(nèi)部的工作流程。(源碼環(huán)境為Android8.0)
1. 先來看Handler類:
1.1 構(gòu)造方法:
Handler的構(gòu)造方法總共有如下幾個(gè),最終實(shí)現(xiàn)為下面兩個(gè)方法:
public Handler(Callback callback, boolean async) {
? ? if (FIND_POTENTIAL_LEAKS) {
? ? ? ? final Class 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;
}
public Handler(Looper looper, Callback callback, boolean async) {
? ? mLooper = looper;
? ? mQueue = looper.mQueue;
? ? mCallback = callback;
? ? mAsynchronous = async;
}
最終都調(diào)至Handler(Callback callback, boolean async)和Handler(Looper looper, Callback callback, boolean async),看一下源碼可知,主要為初始化幾個(gè)變量:mLooper、mQueue、mCallback,mAsynchronous,前三個(gè)變量非常重要,有以下幾個(gè)結(jié)論:
a.一個(gè)Handler中含有一個(gè)Looper
b.Handler中持有的MessageQueue源于Looper中,與Looper中該變量行為一致
c.一個(gè)Handler中含有一個(gè)Callback
Handler中還有如下幾個(gè)重要的方法,提供了Handler對外的能力:
1.2 obtainMessage方法,對外提供一個(gè)獲取Message緩存池中Message的方法,避免應(yīng)用產(chǎn)生過多的Message對象。根據(jù)參數(shù)的不同,重載有多個(gè)該方法,實(shí)現(xiàn)原理都一樣,以其中之一分析一下:
//obtainMessage@Handler.java
public final Message obtainMessage()
{
? ? return Message.obtain(this);
}
//obtain@Message.java
public static Message obtain(Handler h) {
? ? Message m = obtain();
? ? m.target = h;
? ? return m;
}
// obtain@Message.java
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();
}
sPool提供復(fù)用功能的實(shí)現(xiàn),其存儲結(jié)構(gòu)為鏈表,通過sPoolSize的大小及SPool頭部指針位置作到這一點(diǎn),感興趣的同學(xué)可以研究下
1.3 post方法、sendMessage方法,Handler提供了多個(gè)post方法,按參數(shù)不同,提供了諸如指定時(shí)間、延時(shí)的功能,基本功能是一樣的,以其中某一個(gè)方法說一下其實(shí)現(xiàn):
public final boolean post(Runnable r)
{
? return? sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
? ? Message m = Message.obtain();
? ? m.callback = r;
? ? return m;
}
從getPostMessage方法可以看出,傳入的Runnable被Message所持有。
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
? ? if (delayMillis < 0) {
? ? ? ? delayMillis = 0;
? ? }
? ? return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
? ? msg.target = this;
? ? if (mAsynchronous) {
? ? ? ? msg.setAsynchronous(true);
? ? }
? ? return queue.enqueueMessage(msg, uptimeMillis);
}
由上面可知如下結(jié)論:
a.post方法的實(shí)現(xiàn)是與sendMessage一致的,最終都調(diào)至sendMessage中
b.干了個(gè)什么事呢:得到一個(gè)message,將它的callback設(shè)為傳入的callback(如果有的話),將它的target設(shè)為自身,然后調(diào)用MessageQueue的enqueueMessage處理該Message,實(shí)現(xiàn)原理講到MessageQueue再行討論。
1.4 dispatchMessage方法,該方法從Handler發(fā)起流程中難以看到在什么地方調(diào)用了,是一個(gè)消息處理時(shí)的回調(diào),先講一下該方法的邏輯,后面再說調(diào)用時(shí)機(jī)
public void dispatchMessage(Message msg) {
? ? if (msg.callback != null) {
? ? ? ? handleCallback(msg);
? ? } else {
? ? ? ? if (mCallback != null) {
? ? ? ? ? ? if (mCallback.handleMessage(msg)) {
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? handleMessage(msg);
? ? }
}
private static void handleCallback(Message message) {
? ? message.callback.run();
}
從上面的邏輯中看到如下結(jié)論:
消費(fèi)該Hanlder事件總共有三種可能的途徑,分別為Message中的callback、Handler所持有的Callback對象、Handler的自身的handleMessage方法(一般寫法是構(gòu)造匿名子類,實(shí)現(xiàn)該方法),三種途徑的優(yōu)先級從高到低。
Handler在該機(jī)制中的作用為:
a.對外提供可復(fù)用的Message
b.對外提供發(fā)消息的接口
c.對外提供回調(diào)的實(shí)現(xiàn),三種方式
2.Looper類
在主線程中使用Handler,看不到Looper,因?yàn)橄到y(tǒng)已經(jīng)幫我們自動生成了Looper,在工作線程中使用Handler則必須先調(diào)用Looper的prepare生成Looper,否則會報(bào)錯(cuò),原因如下:
測試代碼:
Thread t =? new Thread(new Runnable() {
? ? @Override
? ? public void run() {
? ? ? ? Handler handler = new Handler();
? ? }
});
t.start();
運(yùn)行后報(bào)錯(cuò):
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Handler最終會調(diào)至(1.1中第一個(gè)構(gòu)造方法)
if (mLooper == null) {
? ? ? ? throw new RuntimeException(
? ? ? ? ? ? "Can't create handler inside thread that has not called Looper.prepare()");
? ? }
因此正確的寫法為:
Thread t =? new Thread(new Runnable() {
? ? @Override
? ? public void run() {
? ? ? ? Looper.prepare();
? ? ? ? Handler handler = new Handler();
? ? ? ? // ignore
? ? ? ? Looper.loop();
? ? }
});
2.1 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));
}
sThreadLocal變量定義如下:
static final ThreadLocal sThreadLocal = new ThreadLocal();
使用ThreadLocal類對Looper進(jìn)行了一層封裝。
像c++的內(nèi)聯(lián)函數(shù)一樣,此處我們直接內(nèi)聯(lián)一下ThreadLocal這個(gè)類,看一下該類的作用,先從Looper中跳出去一下
--------------------------------此處插入ThreadLocal類----------------------------------
3. ThreadLocal類
ThreadLocal達(dá)到的目的是:每一個(gè)ThreadLocal的變量在多個(gè)線程中都有一份copy,相互間獨(dú)立存儲,互不影響,但變量名只有一個(gè)。也就是說對于該變量的使用方來講,看起來像是只定義了一個(gè)變量,但實(shí)際上在多線程環(huán)境中,有互不影響的、每個(gè)線程都有一份的對象存在。如何作到這一點(diǎn)呢,是通過其對外提供的get方法和set方法做到的。
3.1 先來看set方法:
public void set(T value) {
? ? Thread t = Thread.currentThread();
// 第一步,拿到每個(gè)線程所對應(yīng)的ThreadLocalMap
? ? ThreadLocalMap map = getMap(t);
// 第二步,將該值存入或更新map的對應(yīng)位置
? ? if (map != null)
? ? ? ? map.set(this, value);
? ? else
? ? ? ? createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
? ? return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
? ? t.threadLocals = new ThreadLocalMap(this, firstValue);
}
// ThreadLocalMap的構(gòu)造方法
ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
? ? table = new Entry[INITIAL_CAPACITY];
? ? int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
? ? table[i] = new Entry(firstKey, firstValue);
? ? size = 1;
? ? setThreshold(INITIAL_CAPACITY);
}
// set@ThreadLocalMap
private void set(ThreadLocal key, Object value) {
? ? // We don't use a fast path as with get() because it is at
? ? // least as common to use set() to create new entries as
? ? // it is to replace existing ones, in which case, a fast
? ? // path would fail more often than not.
? ? Entry[] tab = table;
? ? int len = tab.length;
? ? int i = key.threadLocalHashCode & (len-1);
? ? for (Entry e = tab[i];
? ? ? ? e != null;
? ? ? ? e = tab[i = nextIndex(i, len)]) {
? ? ? ? ThreadLocal k = e.get();
? ? ? ? if (k == key) {
? ? ? ? ? ? e.value = value;
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? if (k == null) {
? ? ? ? ? ? replaceStaleEntry(key, value, i);
? ? ? ? ? ? return;
? ? ? ? }
? ? }
? ? tab[i] = new Entry(key, value);
? ? int sz = ++size;
? ? if (!cleanSomeSlots(i, sz) && sz >= threshold)
? ? ? ? rehash();
}
上述邏輯第一步拿到每個(gè)線程的ThreadLocalMap對象
// threadlocals#Thread
ThreadLocal.ThreadLocalMap threadLocals = null;
也就是說每個(gè)線程維護(hù)一個(gè)ThreadLocalMap來存儲該線程所用到的所有ThreadLocal變量,ThreadLocalMap的實(shí)現(xiàn)原理與HashMap基本一致,之前討論過HashMap的實(shí)現(xiàn)原理,感興趣的同學(xué)對比一下源碼就能明白。
第二步中將傳入的值存入ThreadLocalMap的對應(yīng)位置,該位置的key由ThreadLocal本身的hash值去運(yùn)算得到的。從上面的代碼中可以看出。每一個(gè)線程持有一個(gè)ThreadLocalMap,set的value將和ThreadLocal自身組成key-value結(jié)構(gòu)存在于該Map中。
3.2 get方法
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();
}
private T setInitialValue() {
? ? T value = initialValue();
? ? Thread t = Thread.currentThread();
? ? ThreadLocalMap map = getMap(t);
? ? if (map != null)
? ? ? ? map.set(this, value);
? ? else
? ? ? ? createMap(t, value);
? ? return value;
}
理解了set方法之后,get方法就較為簡單了,反向拿到存入的值即可,ThreadLocal對象本身在多個(gè)線程中只有一份,但通過其set和get,可以得到其包裝對象在每個(gè)線程中只有一份。
--------------------------ThreadLocal分析完畢,回至Looper----------------------------------
Looper的prepare為一個(gè)靜態(tài)方法,目的是可以生成每個(gè)線程都有一份的Looper
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));
}
2.2 Looper構(gòu)造方法:
private Looper(boolean quitAllowed) {
? ? mQueue = new MessageQueue(quitAllowed);
? ? mThread = Thread.currentThread();
}
持有一個(gè)MessageQueue對象,持有當(dāng)前的線程對象
2.3 loop方法
public static void loop() {
// 第一步:myLooper的實(shí)現(xiàn)看下方,得到當(dāng)前線程的Looper
? ? 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;
? ? // Make sure the identity of this thread is that of the local process,
? ? // and keep track of what that identity token actually is.
? ? Binder.clearCallingIdentity();
? ? final long ident = Binder.clearCallingIdentity();
// 第二步:定義一個(gè)無限循環(huán)體,遍歷MessageQueue,取其中的有效Message,進(jìn)行處理,處理語名為:msg.target.dispatchMessage(msg);該方法請看上面1.4
? ? 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
? ? ? ? final Printer logging = me.mLogging;
? ? ? ? if (logging != null) {
? ? ? ? ? ? logging.println(">>>>> Dispatching to " + msg.target + " " +
? ? ? ? ? ? ? ? ? ? msg.callback + ": " + msg.what);
? ? ? ? }
? ? ? ? final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
? ? ? ? final long traceTag = me.mTraceTag;
? ? ? ? if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
? ? ? ? ? ? Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
? ? ? ? }
? ? ? ? final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
? ? ? ? final long end;
? ? ? ? try {
? ? ? ? ? ? msg.target.dispatchMessage(msg);
? ? ? ? ? ? end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
? ? ? ? } finally {
? ? ? ? ? ? if (traceTag != 0) {
? ? ? ? ? ? ? ? Trace.traceEnd(traceTag);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if (slowDispatchThresholdMs > 0) {
? ? ? ? ? ? final long time = end - start;
? ? ? ? ? ? if (time > slowDispatchThresholdMs) {
? ? ? ? ? ? ? ? Slog.w(TAG, "Dispatch took " + time + "ms on "
? ? ? ? ? ? ? ? ? ? ? ? + Thread.currentThread().getName() + ", h=" +
? ? ? ? ? ? ? ? ? ? ? ? msg.target + " cb=" + msg.callback + " msg=" + msg.what);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? 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);
? ? ? ? }
// 此處實(shí)現(xiàn)Message的循環(huán)利用
? ? ? ? msg.recycleUnchecked();
? ? }
}
public static @Nullable Looper myLooper() {
? ? return sThreadLocal.get();
}
在loop的處理中,有一點(diǎn)需重點(diǎn)關(guān)注,loop在線程中是一個(gè)無限循環(huán),跳出該循環(huán)的條件為MessageQueue的next返回值為空,看一下4.2的next方法實(shí)現(xiàn),返回空依賴于mQuitting變量,也就是說在線程中不需要一直等待事件時(shí),要把MessageQueue該變量置為true,設(shè)置入口為quit@Looper
2.4 quit方法
public void quit() {
? ? mQueue.quit(false);
}
//quit@MessageQueue
void quit(boolean safe) {
? ? if (!mQuitAllowed) {
? ? ? ? throw new IllegalStateException("Main thread not allowed to quit.");
? ? }
? ? synchronized (this) {
? ? ? ? if (mQuitting) {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? mQuitting = true;
? ? ? ? if (safe) {
? ? ? ? ? ? removeAllFutureMessagesLocked();
? ? ? ? } else {
? ? ? ? ? ? removeAllMessagesLocked();
? ? ? ? }
? ? ? ? // We can assume mPtr != 0 because mQuitting was previously false.
? ? ? ? nativeWake(mPtr);
? ? }
}
總結(jié)一下:Looper在Handler機(jī)制中起的作用是:
a.提供每個(gè)線程唯一的實(shí)例
b.觸發(fā)MessageQueue的循環(huán)遍歷
4. MessageQueue類
顧名思義,該類需提供三個(gè)能力:
a.Message隊(duì)列存儲
b.Message入隊(duì)
c.Message出隊(duì)
Message隊(duì)列以鏈表形式存儲,其頭部指針存放于mMessages
4.1 enqueueMessage方法,該方法用于Message入隊(duì)
boolean enqueueMessage(Message msg, long when) {
? ? if (msg.target == null) {
? ? ? ? throw new IllegalArgumentException("Message must have a target.");
? ? }
? ? if (msg.isInUse()) {
? ? ? ? throw new IllegalStateException(msg + " This message is already in use.");
? ? }
? ? synchronized (this) {
? ? ? ? if (mQuitting) {
? ? ? ? ? ? IllegalStateException e = new IllegalStateException(
? ? ? ? ? ? ? ? ? ? msg.target + " sending message to a Handler on a dead thread");
? ? ? ? ? ? Log.w(TAG, e.getMessage(), e);
? ? ? ? ? ? msg.recycle();
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? msg.markInUse();
? ? ? ? msg.when = when;
? ? ? ? Message p = mMessages;
? ? ? ? boolean needWake;
// 以下為入隊(duì)的關(guān)鍵代碼,找到鏈表的隊(duì)尾,放入該Message
? ? ? ? if (p == null || when == 0 || when < p.when) {
? ? ? ? ? ? // New head, wake up the event queue if blocked.
? ? ? ? ? ? msg.next = p;
? ? ? ? ? ? mMessages = msg;
? ? ? ? ? ? needWake = mBlocked;
? ? ? ? } else {
? ? ? ? ? ? // Inserted within the middle of the queue.? Usually we don't have to wake
? ? ? ? ? ? // up the event queue unless there is a barrier at the head of the queue
? ? ? ? ? ? // and the message is the earliest asynchronous message in the queue.
? ? ? ? ? ? needWake = mBlocked && p.target == null && msg.isAsynchronous();
? ? ? ? ? ? Message prev;
// 注意,入隊(duì)的時(shí)候,已經(jīng)按時(shí)間次序?qū)essage插入隊(duì)列中的合適位置
? ? ? ? ? ? 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;
}
需要注意,在上面的入隊(duì)處理中,要按Handler傳入的執(zhí)行時(shí)間插入
enqueueMessage調(diào)用的入口請查看1.3
4.2 next方法,該方法用于MessageQueue出隊(duì)
Message next() {
? ? // Return here if the message loop has already quit and been disposed.
? ? // This can happen if the application tries to restart a looper after quit
? ? // which is not supported.
? ? final long ptr = mPtr;
? ? if (ptr == 0) {
? ? ? ? return null;
? ? }
? ? int pendingIdleHandlerCount = -1; // -1 only during first iteration
? ? int nextPollTimeoutMillis = 0;
? ? for (;;) {
? ? ? ? if (nextPollTimeoutMillis != 0) {
? ? ? ? ? ? Binder.flushPendingCommands();
? ? ? ? }
? ? ? ? nativePollOnce(ptr, nextPollTimeoutMillis);
? ? ? ? synchronized (this) {
? ? ? ? ? ? // Try to retrieve the next message.? Return if found.
? ? ? ? ? ? final long now = SystemClock.uptimeMillis();
? ? ? ? ? ? Message prevMsg = null;
// 第一步:拿到鏈表的頭部
? ? ? ? ? ? Message msg = mMessages;
// 第二步:取到最早入隊(duì)的有效的Message
? ? ? ? ? ? if (msg != null && msg.target == null) {
? ? ? ? ? ? ? ? // 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) {
? ? ? ? ? ? ? ? ? ? // Next message is not ready.? Set a timeout to wake up when it is ready.
? ? ? ? ? ? ? ? ? ? nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? // Got a 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;
? ? ? ? ? ? }
? ? ? ? ? ? // Process the quit message now that all pending messages have been handled.
? ? ? ? ? ? if (mQuitting) {
? ? ? ? ? ? ? ? dispose();
? ? ? ? ? ? ? ? return null;
? ? ? ? ? ? }
? ? ? ? ? ? // If first time idle, then get the number of idlers to run.
? ? ? ? ? ? // Idle handles only run if the queue is empty or if the first message
? ? ? ? ? ? // in the queue (possibly a barrier) is due to be handled in the future.
? ? ? ? ? ? if (pendingIdleHandlerCount < 0
? ? ? ? ? ? ? ? ? ? && (mMessages == null || now < mMessages.when)) {
? ? ? ? ? ? ? ? pendingIdleHandlerCount = mIdleHandlers.size();
? ? ? ? ? ? }
? ? ? ? ? ? if (pendingIdleHandlerCount <= 0) {
? ? ? ? ? ? ? ? // No idle handlers to run.? Loop and wait some more.
? ? ? ? ? ? ? ? mBlocked = true;
? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? }
? ? ? ? ? ? if (mPendingIdleHandlers == null) {
? ? ? ? ? ? ? ? mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
? ? ? ? ? ? }
? ? ? ? ? ? mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
? ? ? ? }
? ? ? ? // Run the idle handlers.
? ? ? ? // We only ever reach this code block during the first iteration.
? ? ? ? for (int i = 0; i < pendingIdleHandlerCount; i++) {
? ? ? ? ? ? final IdleHandler idler = mPendingIdleHandlers[i];
? ? ? ? ? ? mPendingIdleHandlers[i] = null; // release the reference to the handler
? ? ? ? ? ? boolean keep = false;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? keep = idler.queueIdle();
? ? ? ? ? ? } catch (Throwable t) {
? ? ? ? ? ? ? ? Log.wtf(TAG, "IdleHandler threw exception", t);
? ? ? ? ? ? }
? ? ? ? ? ? if (!keep) {
? ? ? ? ? ? ? ? synchronized (this) {
? ? ? ? ? ? ? ? ? ? mIdleHandlers.remove(idler);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? // Reset the idle handler count to 0 so we do not run them again.
? ? ? ? pendingIdleHandlerCount = 0;
? ? ? ? // While calling an idle handler, a new message could have been delivered
? ? ? ? // so go back and look again for a pending message without waiting.
? ? ? ? nextPollTimeoutMillis = 0;
? ? }
}
next方法的調(diào)用入口位于2.3中
小結(jié)一下,通過上面的代碼講解,可以得到以下幾個(gè)結(jié)論:
1. 首先Handler對象本身位于構(gòu)造Handler的當(dāng)前線程,他的事件要發(fā)往那個(gè)線程,取決于構(gòu)造方法傳 的Looper變量
2. MessageQueue與Looper位于Handler所要發(fā)往的工作線程中,Looper持有MessageQueue對象,MessageQueue中看不到Looper
3. Looper與線程為1對1的關(guān)系,也就是說一個(gè)線程只有一個(gè)Looper,一個(gè)Looper只服務(wù)于一個(gè)線程,達(dá)到這個(gè)目的是通過ThreadLocal包裝Looper實(shí)現(xiàn)的
4. 從線程的角度講,Handler對象自身與線程沒有任何關(guān)系,它是通過Looper持有的MessageQueue實(shí)現(xiàn)向Looper所服務(wù)的線程事件隊(duì)列(MessageQueue)插入事件(Message)的
看一下文章開頭所說的幾個(gè)問題是不是已經(jīng)有了答案:
a.Handler是如何實(shí)現(xiàn)多個(gè)線程之前事件傳遞的?
請看上面總結(jié)的第4點(diǎn)
b.Handler、Message、MessageQueue、Looper相互之間的數(shù)量比是多少,都是1:1嗎?
Handler n--1 Looper(以主線程為例,主線程的Looper可以定義非常多Handler)
Looper持有一個(gè)MessageQueue(不可逆,看上面總結(jié)的第2點(diǎn))
MessageQueue 1--n Message
c.每個(gè)變量運(yùn)行的線程是那個(gè)?
Handler位于定義線程、Looper、MessageQueue位于工作線程,線程的輪詢依賴于Looper.loop
d.ThreadLocal是怎么回事,在Handler機(jī)制中起什么作用?
可查看代碼分析部分的第3部分