一、提出問題
面試時(shí)常被問到的問題:
- 簡述 Android 消息機(jī)制
- Android 中 Handler,Looper,MessageQueue,Message 有什么關(guān)系?
這倆問題其實(shí)是一個(gè)問題,其實(shí)只要搞清楚了 Handler,Looper,MessageQueue,Message 的作用和聯(lián)系,就理解了 Android 的 Handler 消息機(jī)制。那么再具體一點(diǎn):
- 為什么在主線程可以直接使用 Handler?
- Looper 對(duì)象是如何綁定 MessageQueue 的?
- MessageQueue 里的消息從哪里來?Handler是如何往MessageQueue中插入消息的?
- Message 是如何綁定 Handler 的?
- Handler 如何綁定 MessageQueue?
- 關(guān)于 handler,在任何地方 new handler 都是什么線程下?
- Looper 循環(huán)拿到消息后怎么處理?
二、解決問題
那么,我們從主線程的消息機(jī)制開始分析:
2.1 主線程 Looper 的創(chuàng)建和循環(huán)
Android 應(yīng)用程序的入口是 main 函數(shù),主線程 Looper 的創(chuàng)建也是在這里完成的。
ActivityThread --> main() 函數(shù)
public static void main(){
// step1: 創(chuàng)建主線程Looper對(duì)象
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
// 綁定應(yīng)用進(jìn)程,布爾標(biāo)記是否為系統(tǒng)進(jìn)程
thread.attach(false);
// 實(shí)例化主線程 Handler
if(sMainThreadHandler == null){
sMainThreadHandler = thread.getHandler();
}
// step2: 開始循環(huán)
Loop.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper.prepareMainLooper()
用來創(chuàng)建主線程的 Looper 對(duì)象,接下來先看這個(gè)方法的實(shí)現(xiàn)。
2.1.1 創(chuàng)建主線程 Looper
Looper --> prepareMainLooper()
private static Looper sMainLooper; // guarded by Looper.class
public static void prepareMainLooper(){
// step1: 調(diào)用本類 prepare 方法
prepare(false);
// 線程同步,如果變量 sMainLooper 不為空拋出主線程 Looper 已經(jīng)創(chuàng)建
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
// step2: 調(diào)用本類 myLooper 方法
sMainLooper = myLooper();
}
}
prepareMainLooper()
方法主要是使用 prepare(false)
創(chuàng)建當(dāng)前線程的 Looper 對(duì)象,再使用 myLooper()
方法來獲取當(dāng)前線程的 Looper 對(duì)象。
step1: Looper --> prepare()
// ThreadLocal 為每個(gè)線程保存單獨(dú)的變量
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
// Looper 類的 MessageQueue 變量
final MessageQueue mQueue;
// quitAllowed 是否允許退出,這里是主線程的 Looper 不可退出
private static void prepare(boolean quitAllowed) {
// 首先判定 Looper 是否存在
if(sThreadLocal.get() != null){
throw new RuntimeException("Only one Looper may be created per thread");
}
// 保存線程的副本變量
sThreadLoacal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
prepare()
方法中用 ThreadLocal 來保存主線程的 Looper 對(duì)象。ThreadLocal 可以看作是一個(gè)用來儲(chǔ)存數(shù)據(jù)的類,類似 HashMap、ArrayList等集合類,它存放著屬于當(dāng)前線程的變量。ThreadLocal 提供了 get/set 方法分別用來獲取和保存變量。
比如在主線程通過prepare()
方法來創(chuàng)建 Looper 對(duì)象,并使用sThreadLoacal.set(new Looper(quitAllowed))
來保存主線程的 Looper 對(duì)象,那么在主線程調(diào)用myLooper()
(實(shí)際調(diào)用了sThreadLocal.get()
方法) 就是通過 ThreadLocal 來獲取主線程的 Looper 對(duì)象。如果在子線程調(diào)用這些方法就是通過 ThreadLocal 保存和獲取屬于子線程的 Looper 對(duì)象。
更多關(guān)于 ThreadLocal 的原理:
問題1:為什么在主線程可以直接使用 Handler?
因?yàn)橹骶€程已經(jīng)創(chuàng)建了 Looper 對(duì)象并開啟了消息循環(huán),通過上文的代碼就可以看出來。
問題2:Looper 對(duì)象是如何綁定 MessageQueue 的?或者說 Looper 對(duì)象創(chuàng)建 MessageQueue 過程。
很簡單,Looper 有個(gè)一成員變量 mQueue,它就是 Looper 對(duì)象默認(rèn)保存的 MessageQueue。上面代碼中 Looper 有一個(gè)構(gòu)造器,新建 Looper 對(duì)象時(shí)會(huì)直接創(chuàng)建 MessageQueue 并賦值給 mQueue。
問題2解決:在 new Looper 時(shí)就創(chuàng)建了 MessageQueue 對(duì)象并賦值給 Looper 的成員變量 mQueue。
step2: Looper --> myLooper()
// 也就是使用本類的ThreadLocal對(duì)象獲取之前創(chuàng)建保存的Looper對(duì)象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
這個(gè)方法就是通過 sThreadLocal 變量獲取當(dāng)前線程的 Looper 對(duì)象,比較常用的一個(gè)方法。上文主線程 Looper 對(duì)象創(chuàng)建后使用該方法獲取了 Looper 對(duì)象。
2.1.2 開始循環(huán)處理消息
回到最開始的 main()
函數(shù),在創(chuàng)建了 Looper 對(duì)象以后就調(diào)用了 Looper.loop()
來循環(huán)處理消息,貼一下大致代碼:
public static void main(){
// step1: 創(chuàng)建主線程Looper對(duì)象
Looper.prepareMainLooper();
...
// step2: 開始循環(huán)
Loop.loop();
}
Looper --> loop()
public static void loop() {
// step1: 獲取當(dāng)前線程的 Looper 對(duì)象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// step2: 獲取 Looper 保存的 MessageQueue 對(duì)象
final MessageQueue queue = me.mQueue;
...
// step3: 循環(huán)讀取消息,如果有則調(diào)用消息對(duì)象中儲(chǔ)存的 handler 進(jìn)行發(fā)送
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
// step4: 使用 Message 對(duì)象保存的 handler 對(duì)象處理消息
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
msg.recycleUnchecked();
}
}
- step1 :
myLooper()
方法就是通過 ThreadLocal 獲取當(dāng)前線程的 Looper 對(duì)象,注意在哪個(gè)線程使用該方法就獲取的該線程的 Looper 對(duì)象。 - step2 :
me.mQueue
,這個(gè) mQueue 就是上面問題2所說的在 Looper 對(duì)象創(chuàng)建時(shí)新建的 MessageQueue 變量。 - step3 :接下來是一個(gè) for 循環(huán),首先通過
queue.next()
來提取下一條消息,具體是怎么提取的可以參考下面文章的 4.2 節(jié):
獲取到下一條消息,如果 MessageQueue 中沒有消息,就會(huì)進(jìn)行阻塞。那么如果存在消息,它又是怎么放入 MessageQueue 的呢?或者說MessageQueue 里的消息從哪里來?Handler是如何往MessageQueue中插入消息的?先不說這個(gè),把這個(gè)問題叫作問題3后面分析。
- step4 :
msg.target.dispatchMessage(msg);
這個(gè)方法最終會(huì)調(diào)用 Handler 的handleMessage(msg)
方法。同時(shí)這里又產(chǎn)生個(gè)問題:msg.target
是何時(shí)被賦值的?,也就是說Message 是如何綁定 Handler 的?先稱之為問題4。那么接著看 Handler 的dispatchMessage
方法:
Handler --> dispatchMessage
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();
}
public void handleMessage(Message msg) {
}
可以看到該方法最后執(zhí)行了 handleMessage()
方法,這是一個(gè)空方法也就是需要我們覆寫并實(shí)現(xiàn)的。另外 dispatchMessage()
也體現(xiàn)出一個(gè)問題:
消息分發(fā)的優(yōu)先級(jí):
- Message 的回調(diào)方法:
message.callback.run();
優(yōu)先級(jí)最高; - Handler 的回調(diào)方法:
mCallback.handleMessage(msg)
優(yōu)先級(jí)次于上方; - Handler 的回調(diào)方法:
handleMessage()
優(yōu)先級(jí)最低。
到這里 Looper 循環(huán)并通過 Handler 發(fā)送消息有一個(gè)整體的流程了,接下來分析 Handler 在消息機(jī)制中的主要作用以及和 Looper、Message 的關(guān)系。
2.2 Handler 的創(chuàng)建和作用
上面說到 loop()
方法在不斷從消息隊(duì)列 MessageQueue 中取出消息(queue.next()
方法),如果沒有消息則阻塞,反之交給 Message 綁定的 Handler 處理。回顧一下沒解決的兩個(gè)問題:
- 問題3:MessageQueue 里的消息從哪里來?Handler 是如何往 MessageQueue 中插入消息的?
- 問題4:
msg.target
是何時(shí)被賦值的?,也就是說Message 是如何綁定 Handler 的?
既然要解決 Handler 插入消息的問題,就要看 Handler 發(fā)送消息的過程。
2.2.1 Handler 發(fā)送消息
Handler --> sendMessage(Message msg);
final MessageQueue mQueue;
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
// 發(fā)送延時(shí)消息
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
// 指定時(shí)間發(fā)送消息
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);
}
// 處理消息,賦值 Message 對(duì)象的 target,消息隊(duì)列插入消息
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
可以看到調(diào)用 sendMessage(Message msg)
方法最終會(huì)調(diào)用到 enqueueMessage()
方法,這個(gè)方法主要有兩個(gè)作用:賦值 Message 對(duì)象的 target、消息隊(duì)列插入消息。
- 賦值 msg 的 target:
msg.target = this
把發(fā)送消息的 Handler 賦值給 msg 對(duì)象的 target。那么問題 4 就解決了:Handler 執(zhí)行發(fā)送消息的過程中將自己綁定給了 Message 的 target,這樣兩者之間就產(chǎn)生了聯(lián)系; - 消息隊(duì)列插入消息:
queue.enqueueMessage(msg, uptimeMillis)
queue 是 MessageQueue 的一個(gè)實(shí)例,queue.enqueueMessage(msg, uptimeMillis)
是執(zhí)行 MessageQueue 的enqueueMessage
方法來插入消息。這樣問題 3 就找到答案:Handler 在發(fā)送消息的時(shí)候執(zhí)行 MessageQueue 的enqueueMessage
方法來插入消息;關(guān)于 MessageQueue 是怎么執(zhí)行插入消息的過程,參考下方文章 4.3 節(jié)
- 上面 Handler 發(fā)送消息使用了 MessageQueue 的實(shí)例 queue,可以看到這個(gè) queue 是上一個(gè)方法
sendMessageAtTime
中由 Handler 的成員變量 mQueue 賦值的,那么 mQueue 是哪來的?問題 5:Handler 如何綁定 MessageQueue?先劇透一下 Handler 綁定的是 Looper 的 MessageQueue 對(duì)象,Looper 的 MessageQueue 對(duì)象是在 Looper 創(chuàng)建時(shí)就 new 的。
要了解 Handler 的 MessageQueue 對(duì)象是怎么賦值的就要看 Handler 的構(gòu)造函數(shù)了,Handler 創(chuàng)建的時(shí)候作了一些列操作比如獲取當(dāng)前線程的 Looper,綁定 MessageQueue 對(duì)象等。
2.2.2 Handler 的創(chuàng)建
下面是 Handler 無參構(gòu)造器和主要的構(gòu)造器,另外幾個(gè)重載的構(gòu)造器有些是通過傳遞不同參數(shù)調(diào)用包含兩個(gè)參數(shù)的構(gòu)造器。兩個(gè)參數(shù)構(gòu)造函數(shù)第一個(gè)參數(shù)為 callback 回調(diào),第二個(gè)函數(shù)用來標(biāo)記消息是否異步。
// 無參構(gòu)造器
public Handler() {
this(null, 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());
}
}
// step1:獲取當(dāng)前線程 Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// step2:獲取 Looper 對(duì)象綁定的 MessageQueue 對(duì)象并賦值給 Handler 的 mQueue
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
- step1:調(diào)用
myLooper()
方法,該方法是使用 sThreadLocal 對(duì)象獲取當(dāng)前線程的 Looper 對(duì)象,回顧一下:
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
如果獲取的 Looper 對(duì)象為 null,說明沒有執(zhí)行 Looper.prepare()
為當(dāng)前線程保存 Looper 變量,就會(huì)拋出 RuntimeException。這里又說明了Handler 必須在有 Looper 的線程中使用,報(bào)錯(cuò)不說,沒有 Looper 就無法綁定 MessageQueue 對(duì)象也就無法進(jìn)行更多有關(guān)消息的操作。
- step2:
mQueue = mLooper.mQueue
說明了 Handler 的 MessageQueue 對(duì)象是由當(dāng)前線程 Looper 的 MessageQueue 對(duì)象賦值的。這里問題 5 解決:Handler 在創(chuàng)建時(shí)綁定了當(dāng)前線程 Looper 的 MessageQueue 對(duì)象。 - 由于 Handler 和 Looper 可以看作使用的是同一個(gè) MessageQueue 對(duì)象,所以 Handler 和 Looper 可以共享消息隊(duì)列 MessageQueue。Handler 發(fā)送消息(用 mQueue 往消息對(duì)列插入消息),Looper 可以方便的循環(huán)使用 mQueue 查詢消息,如果查詢到消息,就可以用 Message 對(duì)象綁定的 Handler 對(duì)象 target 去處理消息,反之則阻塞。
既然說到了 Handler 的構(gòu)造器,就想到一個(gè)問題:問題 6:關(guān)于 handler,在任何地方 new handler 都是什么線程下?這個(gè)問題要分是否傳遞 Looper 對(duì)象來看。
- 不傳遞 Looper 創(chuàng)建 Handler:
Handler handler = new Handler();
上文就是 Handler 無參創(chuàng)建的源碼,可以看到是通過Looper.myLooper()
來獲取 Looper 對(duì)象,也就是說對(duì)于不傳遞 Looper 對(duì)象的情況下,在哪個(gè)線程創(chuàng)建 Handler 默認(rèn)獲取的就是該線程的 Looper 對(duì)象,那么 Handler 的一系列操作都是在該線程進(jìn)行的。 - 傳遞 Looper 對(duì)象創(chuàng)建 Handler:
Handler handler = new Handler(looper);
那么看看傳入 Looper 的構(gòu)造函數(shù):
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
// 第一個(gè)參數(shù)是 looper 對(duì)象,第二個(gè) callback 對(duì)象,第三個(gè)消息處理方式(是否異步)
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
可以看出來傳遞 Looper 對(duì)象 Handler 就直接使用了。所以對(duì)于傳遞 Looper 對(duì)象創(chuàng)建 Handler 的情況下,傳遞的 Looper 是哪個(gè)線程的,Handler 綁定的就是該線程。
到這里 Looper 和 Handler 就有一個(gè)大概的流程了,接下來看一個(gè)簡單的子線程 Handler 使用例子:
new Thread() {
@Override
public void run() {
// step1
Looper.prepare();
// step2
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what == 1){
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"HandlerTest",Toast.LENGTH_SHORT).show();
}
});
// step5
Looper.myLooper().quit();
}
}
};
// step3
handler.sendEmptyMessage(1);
// step4
Looper.loop();
}
}.start();
- step1: 調(diào)用
Looper.prepare();
為當(dāng)前線程創(chuàng)建 Looper 對(duì)象,同時(shí)也就創(chuàng)建了 MessageQueue,之后將該線程的 Looper 對(duì)象保存在 ThreadLocal 中。注意這里的一切操作都在子線程中,如果不調(diào)用Looper.prepare()
就使用 Handler 會(huì)報(bào)錯(cuò)。 - step2: 創(chuàng)建 Handler 對(duì)象,覆寫 handleMessage 處理消息,等待該 Handler 發(fā)送的消息處理時(shí)會(huì)調(diào)用該方法。
- step3: 使用 handler 發(fā)送消息,這里只是示例,畢竟自己給自己發(fā)送消息沒啥必要。發(fā)送的過程中會(huì)將自己賦值給
msg.target
,然后再將消息插入到 Looper 綁定的 MessageQueue 對(duì)象中。 - step4: 調(diào)用
Looper.loop();
首先獲取當(dāng)前線程的 Looper 對(duì)象,根據(jù) Looper 對(duì)象就可以拿到 Looper 保存的 MessageQueue 對(duì)象 mQueue。有了 MessageQueue 對(duì)象就可以 for 循環(huán)獲取它保存的消息 Message 對(duì)象,如果消息不存在就返回 null 阻塞,反之則使用 Message 中保存的 Handler:msg.target
來處理消息,最終調(diào)用 handleMessage 也就是之前覆寫的方法來處理消息。 - step5: 邏輯處理完畢以后,應(yīng)在最后使用 quit 方法來終止消息循環(huán),否則這個(gè)子線程就會(huì)一直處于等待的狀態(tài),而如果退出Looper以后,這個(gè)線程就會(huì)立刻終止,因此建議不需要的時(shí)候終止Looper。
三、總結(jié)和其它
3.1 Handler、Looper、MessageQueue、Message
- Handler 用來發(fā)送消息,創(chuàng)建時(shí)先獲取默認(rèn)或傳遞來的 Looper 對(duì)象,并持有 Looper 對(duì)象包含的 MessageQueue,發(fā)送消息時(shí)使用該 MessageQueue 對(duì)象來插入消息并把自己封裝到具體的 Message 中;
- Looper 用來為某個(gè)線程作消息循環(huán)。Looper 持有一個(gè) MessageQueue 對(duì)象 mQueue,這樣就可以通過循環(huán)來獲取 MessageQueue 所維護(hù)的 Message。如果獲取的 MessageQueue 沒有消息時(shí),便阻塞在 loop 的
queue.next()
中的nativePollOnce()
方法里,反之則喚醒主線程繼續(xù)工作,之后便使用 Message 封裝的 handler 對(duì)象進(jìn)行處理。 - MessageQueue 是一個(gè)消息隊(duì)列,它不直接添加消息,而是通過與 Looper 關(guān)聯(lián)的 Handler 對(duì)象來添加消息。
- Message 包含了要傳遞的數(shù)據(jù)和信息。
3.2 Android中為什么主線程不會(huì)因?yàn)長ooper.loop()里的死循環(huán)卡死?
這是知乎上的問題,感覺問的挺有意思。平時(shí)可能不太會(huì)太深究這些問題,正好有大神回答那就記錄一下吧。
- 為什么不會(huì)因?yàn)樗姥h(huán)卡死?
線程可以看作是一段可執(zhí)行代碼,當(dāng)代碼執(zhí)行完畢線程的生命周期就該終止了。對(duì)于主線程來說我們不希望它執(zhí)行一段時(shí)間后退出,所以簡單做法就是可執(zhí)行代碼是能一直執(zhí)行下去的,死循環(huán)便能保證不會(huì)被退出。既然是死循環(huán)那么怎么去處理消息呢,通過創(chuàng)建新線程的方式。 - 為這個(gè)死循環(huán)準(zhǔn)備了一個(gè)新線程
在進(jìn)入死循環(huán)之前便創(chuàng)建了新binder線程,在代碼ActivityThread.main()中:
public static void main(){
...
Looper.prepareMainLooper();
//創(chuàng)建ActivityThread對(duì)象
ActivityThread thread = new ActivityThread();
//建立Binder通道 (創(chuàng)建新線程)
thread.attach(false);
if(sMainThreadHandler == null){
sMainThreadHandler = thread.getHandler();
}
// step2: 開始循環(huán)
Loop.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
thread.attach(false);便會(huì)創(chuàng)建一個(gè)Binder線程(具體是指ApplicationThread,Binder的服務(wù)端,用于接收系統(tǒng)服務(wù)AMS發(fā)送來的事件),該Binder線程通過Handler將Message發(fā)送給主線程。
- 主線程的死循環(huán)一直運(yùn)行是不是特別消耗CPU資源呢?
其實(shí)不然,這里就涉及到Linux pipe/epoll機(jī)制,簡單說就是在主線程的MessageQueue沒有消息時(shí),便阻塞在loop的queue.next()中的nativePollOnce()方法里,詳情見Android消息機(jī)制1-Handler(Java層),此時(shí)主線程會(huì)釋放CPU資源進(jìn)入休眠狀態(tài),直到下個(gè)消息到達(dá)或者有事務(wù)發(fā)生,通過往pipe管道寫端寫入數(shù)據(jù)來喚醒主線程工作。這里采用的epoll機(jī)制,是一種IO多路復(fù)用機(jī)制,可以同時(shí)監(jiān)控多個(gè)描述符,當(dāng)某個(gè)描述符就緒(讀或?qū)懢途w),則立刻通知相應(yīng)程序進(jìn)行讀或?qū)懖僮鳎举|(zhì)同步I/O,即讀寫是阻塞的。所以說,主線程大多數(shù)時(shí)候都是處于休眠狀態(tài),并不會(huì)消耗大量CPU資。
- Activity的生命周期是怎么實(shí)現(xiàn)在死循環(huán)體外能夠執(zhí)行起來的?
上文 main 函數(shù)有一部分獲取 sMainThreadHandler 的代碼:
final H mH = new H();
public static void main(){
...
if(sMainThreadHandler == null){
sMainThreadHandler = thread.getHandler();
}
...
}
final Handler getHandler() {
return mH;
}
類 H 繼承了 Handler,在主線程創(chuàng)建時(shí)就創(chuàng)建了這個(gè) Handler 用于處理 Binder 線程發(fā)送來的消息。
Activity的生命周期都是依靠主線程的Looper.loop,當(dāng)收到不同Message時(shí)則采用相應(yīng)措施:
在H.handleMessage(msg)方法中,根據(jù)接收到不同的msg,執(zhí)行相應(yīng)的生命周期。
比如收到msg=H.LAUNCH_ACTIVITY,則調(diào)用ActivityThread.handleLaunchActivity()方法,最終會(huì)通過反射機(jī)制,創(chuàng)建Activity實(shí)例,然后再執(zhí)行Activity.onCreate()等方法;
再比如收到msg=H.PAUSE_ACTIVITY,則調(diào)用ActivityThread.handlePauseActivity()方法,最終會(huì)執(zhí)行Activity.onPause()等方法。 上述過程,我只挑核心邏輯講,真正該過程遠(yuǎn)比這復(fù)雜。
3.3 Handler 使用造成內(nèi)存泄露
- 有延時(shí)消息,要在Activity銷毀的時(shí)候移除Messages
- 匿名內(nèi)部類導(dǎo)致的泄露改為匿名靜態(tài)內(nèi)部類,并且對(duì)上下文或者Activity使用弱引用。
具體操作可以參考文章:
參考資料:
《Android 開發(fā)藝術(shù)探索》
Android消息機(jī)制1-Handler(Java層)
Android Handler消息機(jī)制實(shí)現(xiàn)原理