Android中,Handler雖然不是四大組件,但用的次數(shù)也不比Activity个唧,Service等四大組件少渠退。雖然大家都知道怎么使用Handler忙迁,但是我們不能僅僅停留在使用的層面脐彩,對(duì)其機(jī)制的分析會(huì)加深我們對(duì)Android的理解。當(dāng)然了姊扔,最終的目的就是在面試的時(shí)候碾壓面試官惠奸,本系列將會(huì)對(duì)Handler機(jī)制做詳細(xì)的分析。
由于篇幅可能比較長(zhǎng)恰梢,該系列將分文下面幾篇文章:
- Handler,MessageQueue,與Looper三者關(guān)系分析
- HandlerThread源碼分析
- IntentService源碼分析
- Handler常見(jiàn)應(yīng)用場(chǎng)景和常見(jiàn)問(wèn)題分析
Handler,MessageQueue,Looper的關(guān)系分析
要理清這三者的曖昧關(guān)系佛南,我們先分別簡(jiǎn)單介紹一下它們
Handler
A Handler allows you to send and process Message and Runnable
objects associated with a thread's MessageQueue.
如官網(wǎng)描述的,我們可以用Handler發(fā)送并處理Message對(duì)象或者一個(gè)線程對(duì)象删豺,并關(guān)聯(lián)到一個(gè)線程的消息隊(duì)列里共虑,即MessageQueue,而關(guān)聯(lián)的線程就是創(chuàng)建Handler的線程呀页。
Handler使用場(chǎng)景
- 在未來(lái)某個(gè)時(shí)間點(diǎn)上處理Message或者執(zhí)行Runnable
- 將需要執(zhí)行的操作通過(guò)Handler發(fā)送消息在其他線程里執(zhí)行
Lopper
通常線程默認(rèn)是不具備循環(huán)處理消息的能力的妈拌,而Looper就是用來(lái)給線程提供循環(huán)處理消息能力的類(lèi)。
當(dāng)我們需要循環(huán)處理消息時(shí)蓬蝶,我們?cè)趧?chuàng)建Handler的線程里調(diào)用Looper.prepare()準(zhǔn)備好Looper尘分,之后再調(diào)用Looper.loop()開(kāi)始循環(huán)處理消息。
如果我們是在主線程創(chuàng)建的Handler丸氛,就不需要做上面的兩個(gè)操作了培愁,因?yàn)橹骶€程已經(jīng)幫我們處理好了
一個(gè)經(jīng)典的用法如下
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();
}
}
MessageQueue
顧名思義,消息隊(duì)列缓窜。持有Handler發(fā)送的消息列表定续,我們可以使用
Looper.myQueue()來(lái)拿到這個(gè)對(duì)象。
除了上面的三個(gè)大頭外禾锤,還有一個(gè)雖然也很重要私股,但我們不用對(duì)他做太多文章,因?yàn)樗黄鸬匠休d信息的作用恩掷,也就是我們的Message對(duì)象倡鲸。Handler發(fā)送和處理的對(duì)象都是它,可能你會(huì)說(shuō)Handler的方法里不一定要使用Message來(lái)發(fā)送呀黄娘,不著急峭状,等等分析源碼的時(shí)候我們就為什么這么說(shuō)了
工作原理
當(dāng)我們創(chuàng)建Handler時(shí),每個(gè)Handler實(shí)例都會(huì)關(guān)聯(lián)一個(gè)線程以及這個(gè)線程的消息隊(duì)列逼争,這個(gè)線程指的就是創(chuàng)建Handler的線程优床。
怎么理解呢? 其實(shí)很簡(jiǎn)單誓焦,Android里線程無(wú)非就是主線程(或UI線程)和子線程羔巢,從這點(diǎn)入手,我們就可以理解,如果在主線程創(chuàng)建Handler竿秆,會(huì)關(guān)聯(lián)到主線程以及主線程里的消息隊(duì)列, 子線程創(chuàng)建的Handler會(huì)關(guān)聯(lián)到子線程以及子線程的消息隊(duì)列
具體是怎么實(shí)現(xiàn)的呢启摄?我們從源碼入手看看端倪,
初始化
當(dāng)我們new Handler()時(shí)幽钢,會(huì)調(diào)用到下面這個(gè)構(gòu)造方法歉备,其中 Callback是null,async是false
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;
}
溢出堅(jiān)持標(biāo)識(shí)FIND_POTENTIAL_LEAKS默認(rèn)是flase, 故會(huì)先執(zhí)行 Looper.myLooper, 發(fā)現(xiàn)就只調(diào)用了ThreadLocal的get方法返回一個(gè)Looper
public static Looper myLooper() {
return sThreadLocal.get();
}
ThreadLocal里的get實(shí)現(xiàn)
/**
* Returns the value of this variable for the current thread. If an entry
* doesn't yet exist for this variable on this thread, this method will
* create an entry, populating the value with the result of
* {@link #initialValue()}.
*
* @return the current value of the variable for the calling thread.
*/
@SuppressWarnings("unchecked")
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
/**
* Gets Values instance for this thread and variable type.
*/
Values values(Thread current) {
return current.localValues;
}
我們看到匪燕,獲取到當(dāng)前的線程并取得其ThreadLocal.Values成員變量, 而這個(gè)成員變量的初始化的地方也就是在這個(gè)get方法里調(diào)用initializeValues(currentThread)
/**
* Creates Values instance for this thread and variable type.
*/
Values initializeValues(Thread current) {
return current.localValues = new Values();
}
Value的構(gòu)造
/**
* Constructs a new, empty instance.
*/
Values() {
initializeTable(INITIAL_SIZE);
this.size = 0;
this.tombstones = 0;
}
private void initializeTable(int capacity) {
this.table = new Object[capacity * 2];
this.mask = table.length - 1;
this.clean = 0;
this.maximumLoad = capacity * 2 / 3; // 2/3
}
ThreadLocal和Value功能就是提供一個(gè)Map功能的Object數(shù)組來(lái)存儲(chǔ)數(shù)據(jù)蕾羊。
初始化完線程的ThreadLocal.Value后,Looper.myLooper() 最后會(huì)調(diào)用 ThreadLocal get方法里的 values.getAfterMiss(this)
/**
* Gets value for given ThreadLocal after not finding it in the first
* slot.
*/
Object getAfterMiss(ThreadLocal<?> key) {
Object[] table = this.table;
int index = key.hash & mask;
// If the first slot is empty, the search is over.
if (table[index] == null) {
Object value = key.initialValue();
// If the table is still the same and the slot is still empty...
if (this.table == table && table[index] == null) {
table[index] = key.reference;
table[index + 1] = value;
size++;
cleanUp();
return value;
}
// The table changed during initialValue().
put(key, value);
return value;
}
...
}
因?yàn)槭堑谝淮纬跏蓟毖保瑵M足條件 table[index] == null龟再,會(huì)return key.initialValue(),而
protected T initialValue() {
return null;
}
...
什么鬼尼变,看了這么久return一個(gè)null...好吧利凑,那就null吧。
我們回過(guò)頭來(lái)看Handler的初始化嫌术,會(huì)發(fā)現(xiàn)由于mLooper為null會(huì)拋出一個(gè)RuntimeException
Can't create handler inside thread that has not called Looper.prepare()
所以哀澈,我們不得不先調(diào)用 Looper.prepare()
/**
* quitAllowed will be 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));
}
可以看到,在這里給Looper里的ThreadLocal初始化了一個(gè)Looper度气,這樣當(dāng)我們調(diào)用 Looper.myLooper()的時(shí)候割按,其實(shí)就是從ThreadLocal里取出在這里初始化的Looper。
好磷籍,接著我們看Looper的初始化
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper里創(chuàng)建了一個(gè)MessageQueue,并保存當(dāng)前的線程适荣,也就是我們之前一直提到的 Handler會(huì)關(guān)聯(lián)到一個(gè)線程。而Handler里的成員變量mQueue也就是Lopper里的mQueue院领。 到這里初始化就告一段落了
發(fā)送消息
初始化完成后束凑,我們就可以通過(guò)Handler的postxxx, sendxxx方法來(lái)發(fā)送消息
我們看sendEmptyMessage方法就可以發(fā)現(xiàn),層層嵌套最終調(diào)用的是 sendMessageAtTime 方法
sendEmptyMessage
public final boolean sendEmptyMessage(int what) {
return sendEmptyMessageDelayed(what, 0);
}
sendMessageDelayed
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
如果是post一個(gè)Runnable栅盲,它還會(huì)調(diào)用下面這個(gè)方法,將Runnable復(fù)制給Message里的callback成員變量废恋,所以說(shuō)Handler發(fā)送和處理的都是Message對(duì)象
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
sendMessageDelayed
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
sendMessageAtTime
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);
}
最終呢谈秫,就會(huì)調(diào)用enqueueMessage方法,將Message入棧到Looper里的MessageQueue
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
MessageQueue 隊(duì)列的實(shí)現(xiàn)鱼鼓,原理是使用Message鏈表拟烫,有興趣的同學(xué)可以自己去研究一下,我們就不做過(guò)多的闡述迄本。
這樣發(fā)送消息的過(guò)程到這里也基本完結(jié)了
處理消息
你還記得嗎硕淑?當(dāng)我們?cè)谧泳€程里創(chuàng)建Handler的時(shí)候,都會(huì)在run方法里調(diào)用Looper.loop()方法,異步處理Message對(duì)象置媳。如果是在主線程創(chuàng)建的Handler就不是異步了于樟,因?yàn)樗P(guān)聯(lián)的線程是主線程,Handler的handlerMessage回調(diào)是在主線程里執(zhí)行的拇囊。
最后迂曲,我們來(lái)看看Handler最核心的實(shí)現(xiàn),消息的處理 Looper.loop(),
忽略非消息處理的代碼后如下
public static void loop() {
...
// 獲取消息隊(duì)列
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
msg.target.dispatchMessage(msg);
...
msg.recycleUnchecked();
}
}
看著是不是挺簡(jiǎn)單的呢寥袭? 一個(gè)for死循環(huán)路捧,通過(guò)MessageQueue的阻塞方法next 讀取下一個(gè)Message。
取出來(lái)的Message會(huì)拿到target成員變量传黄,即Handler,調(diào)用dispatchMessage杰扫,分發(fā)消息。Handler里的分發(fā)呢膘掰?
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
分發(fā)給callback回調(diào)章姓,或者M(jìn)essage對(duì)象的callback,又或者Handler子類(lèi)里的handlerMessage炭序。
我們可以調(diào)用Looper的quit()方法啤覆,讓隊(duì)列安全的關(guān)閉,避免不必要的消耗惭聂。
或者等待Handler被銷(xiāo)毀窗声,讓系統(tǒng)自動(dòng)回收
public void quit() {
mQueue.quit(false);
}
這樣Handler的整體的工作原理就是這些了,再見(jiàn)Handler辜纲。