Handler概念
Handler主要用于發(fā)送和處理消息和Runable對(duì)象稍途。處理異步操作
源碼解析
- Handler的創(chuàng)建
Handler共有7個(gè)構(gòu)造函數(shù),如下:
1砚婆、無參構(gòu)造函數(shù)械拍,內(nèi)部調(diào)用【6】構(gòu)造函數(shù)
public Handler() {
this(null, false);
}
2、參數(shù):只有Callback的構(gòu)造函數(shù),內(nèi)部調(diào)用【6】構(gòu)造函數(shù)
public Handler(Callback callback) {
this(callback, false);
}
3坷虑、參數(shù):只有async的構(gòu)造函數(shù)甲馋,被系統(tǒng)隱藏,我們不能調(diào)用迄损。內(nèi)部調(diào)用【6】構(gòu)造函數(shù)
public Handler(boolean async) {
this(null, async);
}
4定躏、參數(shù):只有一個(gè)Looper的構(gòu)造函數(shù),內(nèi)部調(diào)用
public Handler(Looper looper) {
this(looper, null, false);
}
5芹敌、參數(shù):有Looper和Callback的構(gòu)造函數(shù)痊远,內(nèi)部調(diào)用
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
6、參數(shù):Callback和async的構(gòu)造函數(shù)党窜,被系統(tǒng)隱藏拗引,我們不能調(diào)用
Callback:用于處理消息的接口。
async:是否是異步處理消息幌衣,默認(rèn)為false矾削,我創(chuàng)建Handler時(shí),系統(tǒng)為我們指定為false
執(zhí)行步驟:
1豁护、調(diào)用 Looper.myLooper()哼凯,獲取Looper。myLooper()方法實(shí)際使用ThreadLocal.get()方法楚里,獲取當(dāng)前線程指定的Looper断部。
2、從獲取的Looper中獲取消息隊(duì)列班缎,MessageQueue
3蝴光、初始化賦值 mCallback和 mAsynchronous
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;
}
Callback接口源碼
public interface Callback {
public boolean handleMessage(Message msg);
}
7、參數(shù):Looper达址、Callback蔑祟、async 構(gòu)造函數(shù)。
主要就是初始化賦值
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
- ThreadLocal
- 簡(jiǎn)介
ThreadLocal只有用于線程內(nèi)的數(shù)據(jù)存儲(chǔ)沉唠,通過他可以在指定的線程內(nèi)存儲(chǔ)數(shù)據(jù)疆虚,數(shù)據(jù)存儲(chǔ)以后,其他線程無法獲取到該數(shù)據(jù)满葛,只有該線程可以獲取到存儲(chǔ)的數(shù)據(jù)
在系統(tǒng)內(nèi)径簿,雖然使用的是同一個(gè)ThreadLocal對(duì)象,但是通過TheadLocal獲取的數(shù)據(jù)不一樣嘀韧,例如Looper
一般線程篇亭,某些數(shù)據(jù)是以線程為作用于,并且不同線程用于不同的數(shù)據(jù)副本的時(shí)候锄贷,就可以考慮使用ThreadLocal
2.ThreadLocal的get()方法
執(zhí)行流程
1暗赶、獲取當(dāng)前線程
2鄙币、獲取當(dāng)前線程的TheadLocalMap
3、如果TheadLocalMap不為空蹂随,則以ThreaLocal當(dāng)前實(shí)例作為Key去取值十嘿,然后返回
4、如果ThreaLocalMap為空岳锁,或者取值為空绩衷,創(chuàng)建ThreadLocal或者設(shè)置默認(rèn)值
public T get() {
//1. 獲取當(dāng)前的線程
Thread t = Thread.currentThread();
//2. 以當(dāng)前線程為參數(shù),獲取一個(gè) ThreadLocalMap 對(duì)象
ThreadLocalMap map = getMap(t);
if (map != null) {
//3. map 不為空激率,則以當(dāng)前 ThreadLocal 對(duì)象實(shí)例作為key值咳燕,去map中取值,有找到直接返回
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
//4. map 為空或者在map中取不到值乒躺,那么走這里招盲,返回默認(rèn)初始值
return setInitialValue();
}
- Looper初始化/Looper.perpare()
1、實(shí)例化MessageQueue
2嘉冒、獲取當(dāng)前線程
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
1曹货、Handler初始化獲取,當(dāng)在主線程定義Handler時(shí)讳推,通過Looper.myLooper()獲取主線程的Looper顶籽。
2、在子線程內(nèi)調(diào)用Looper.prepare()方法初始化银觅,
Looper.prepare()實(shí)際是new一個(gè)Looper之后通過ThreadLoca的set方法礼饱,以ThreadLoca當(dāng)前實(shí)例為key放入到線程內(nèi)的ThreadLocalMap中
如果Looper已經(jīng)被初始化,則拋出異常
RuntimeException("Only one Looper may be created per thread")
總結(jié):
1究驴、所以在主線程創(chuàng)建Handler時(shí)镊绪,我們不需要實(shí)例Looper,因?yàn)樵贏ctivityThread主線程中已經(jīng)初始化了Looper洒忧,而之后我們?cè)谥骶€程使用的Looper都是同一個(gè)Looper
2蝴韭、在子線程實(shí)例Handler時(shí),需要我們?cè)谧泳€程內(nèi)調(diào)用Looper的prepare()方法實(shí)例化Looper
- Handler發(fā)送消息
實(shí)際發(fā)送一個(gè)Message主要是調(diào)用MessageQueue的enqueueMessage方法將消息放入隊(duì)列
//調(diào)用sendMessageDelayed(Message msg, long delayMillis)
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
// 調(diào)用sendMessageAtTime(Message msg, long uptimeMillis)
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//調(diào)用enqueueMessage(queue, msg, uptimeMillis)
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);
}
//調(diào)用MessageQueue的enqueueMessage(msg, uptimeMillis);將消息放入隊(duì)列
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//設(shè)置target為當(dāng)前Handler實(shí)例
msg.target = this;
//如果是異步處理,則設(shè)置Message為同步跑慕,這個(gè) mAsynchronous 標(biāo)識(shí)是我們構(gòu)造 Handler 的時(shí)候傳遞的參數(shù),默認(rèn)為 false
if (mAsynchronous) {
msg.setAsynchronous(true);
}
最后就是真正的進(jìn)隊(duì)方法
return queue.enqueueMessage(msg, uptimeMillis);
}
MessageQueue將消息放入隊(duì)列
消息隊(duì)列是使用鏈表作為數(shù)據(jù)的存儲(chǔ)結(jié)構(gòu)摧找。是可以插隊(duì)的核行,即不存在發(fā)送了延時(shí)消息不會(huì)阻塞消息隊(duì)列。
MessageQueue中存儲(chǔ)一個(gè)頭結(jié)點(diǎn)的Message 蹬耘,而每個(gè)Message中都存儲(chǔ)一個(gè)Message芝雪,這樣根據(jù)消息的執(zhí)行順序設(shè)置Message的next形成了消息隊(duì)列
boolean enqueueMessage(Message msg, long when) {
//如果target為空則拋出異常。target實(shí)際是發(fā)送消息的Handler實(shí)例综苔,之后被用來處理消息
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) {
//如果MessageQueue退出惩系,則釋放消息
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();
///賦值調(diào)用時(shí)間
msg.when = when;
//獲取頭結(jié)點(diǎn)
Message p = mMessages;
boolean needWake;
// //隊(duì)列中沒有消息 或者 時(shí)間為0 或者 比頭結(jié)點(diǎn)的時(shí)間早
//插入到頭結(jié)點(diǎn)中
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
/類似插入排序位岔,找到合適的位置,找到一個(gè)Messgae的next為空或者next的執(zhí)行實(shí)際大于當(dāng)前message的Message
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 將上一個(gè)Message的next設(shè)置個(gè)當(dāng)前Message。將上一個(gè)Message的next設(shè)置為當(dāng)前Message
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
- Looper循環(huán)消息
1堡牡、loop首先判斷Looper是否為空抒抬,如果為空則拋出異常 RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
這就是我們創(chuàng)建非主線程的 Handler為什么要調(diào)用Looper.prepare()的原因。
而主線程中會(huì)在ActivityThread.main() 方法里面調(diào)用了 prepare 方法晤柄,
所以我們創(chuàng)建默認(rèn)(主線程)的 Handler 不需要額外創(chuàng)建 Looper
2擦剑、loop內(nèi)是一個(gè)死循環(huán),取出消息如果為空則退出循環(huán)芥颈,如果不為空則執(zhí)行msg的響應(yīng)的Handler的dispatchMessage(msg)處理消息惠勒。for循環(huán)內(nèi)通過queue.next()取出消息。
// Looper.java 爬坑,省略部分代碼
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 , 從隊(duì)列取出一個(gè)msg
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg); //Handler處理消息
msg.recycleUnchecked(); //回收msg
}
}
MessageQueue的next()如下
//MessageQueue.java ,刪減部分代碼
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
//如果隊(duì)列已經(jīng)停止了(quit or dispose)
return null;
}
for (;;) {
synchronized (this) {
final long now = SystemClock.uptimeMillis(); //獲取當(dāng)前時(shí)間
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
//msg == target 的情況只能是屏障消息纠屋,即調(diào)用postSyncBarrier()方法
//如果存在屏障,停止同步消息盾计,異步消息還可以執(zhí)行
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous()); //找出異步消息售担,如果有的話
}
if (msg != null) {
if (now < msg.when) {
//當(dāng)前消息還沒準(zhǔn)備好(時(shí)間沒到)
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 消息已準(zhǔn)備,可以取出
if (prevMsg != null) {
//有屏障闯估,prevMsg 為異步消息 msg 的前一節(jié)點(diǎn)灼舍,相當(dāng)于拿出 msg ,鏈接前后節(jié)點(diǎn)
prevMsg.next = msg.next;
} else {
//沒有屏障,msg 即頭節(jié)點(diǎn),將 mMessages 設(shè)為新的頭結(jié)點(diǎn)
mMessages = msg.next;
}
msg.next = null; //斷開即將執(zhí)行的 msg
msg.markInUse(); //標(biāo)記為使用狀態(tài)
return msg; //返回取出的消息涨薪,交給Looper處理
}
}
// Process the quit message now that all pending messages have been ha
if (mQuitting) {
//隊(duì)列已經(jīng)退出
dispose();
return null; //返回null后Looper.loop()方法也會(huì)結(jié)束循環(huán)
}
}
}
異步消息并不會(huì)立刻執(zhí)行骑素,而是根據(jù)時(shí)間,完全跟同步消息一樣的順序插入隊(duì)列中刚夺。異步消息與同步消息唯一的區(qū)別就是當(dāng)有消息屏障時(shí)献丑,異步消息還可以執(zhí)行,而同步消息則不行
總結(jié):發(fā)送消息的所在的線程侠姑,不處理消息创橄,只有Looper將消息取出后處理,所以在無論Handler發(fā)送消息所在在哪個(gè)線程莽红,最終處理消息是在Looper.loop()所在的線程
- Handler處理消息
Looper.loop()取出消息后妥畏,調(diào)用msg.target.dispatchMessage(msg)方法處理消息,msg.target就是發(fā)送消息的Handler
消息處理:
1安吁、消息的Runable不為空時(shí)醉蚁,使用Runable處理消息
2、Handler的CallBack不為空時(shí)鬼店,使用CallBack處理消息
3网棍、Handler的handleMessage()處理消息
public void dispatchMessage(Message msg) {
//如果消息的CallBack不為空,則調(diào)用 handleCallback(msg);.Callback就是Runable
if (msg.callback != null) {
handleCallback(msg);
} else {
// 如果Handler的CallBack不為空妇智,則調(diào)用Callback處理下消息滥玷,如果mCallback.handleMessage(msg)返回true氏身,則處理結(jié)束,否則惑畴,將繼續(xù)執(zhí)行Handler的handleMessage(msg);
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//最后上面情況都不滿足時(shí)蛋欣,調(diào)用Handler的handleMessage(msg)處理消息
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
總結(jié):
如果 msg 沒有 callback 的話,那么將會(huì)判斷 mCallback 是否為空桨菜,
這個(gè) mCallback 就是構(gòu)造方法種傳遞的那個(gè) Callback ,如果
mCallback為空,那么就調(diào)用 Handler 的 handleMessage(msg)
方法豁状,否則就調(diào)用 mCallback.handleMessage(msg) 方法,然后根據(jù)
mCallback.handleMessage(msg)的返回值判斷是否攔截消息倒得,如果攔截(返回
true)泻红,則結(jié)束,否則還會(huì)調(diào)用 Handler#handleMessage(msg)方法霞掺。
也就是說:Callback.handleMessage()
的優(yōu)先級(jí)比Handler.handleMessage()要高
谊路。如果存在Callback,并且Callback#handleMessage() 返回了 true
,那么Handler#handleMessage()將不會(huì)調(diào)用。
- Handler.post(Runnable)
無論消息發(fā)送Runable還是msg菩彬,最終消息的載體都是Message缠劝,Runable只是用來處理消息,而最終使用Runable的處理消息使用handleCallback(Message message)骗灶,而該方法內(nèi)部調(diào)用Runable的run方法惨恭,并沒有新建線程
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
//創(chuàng)建消息,將Runable放入現(xiàn)在Message內(nèi)耙旦,用來處理消息
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
- 消息創(chuàng)建
消息的創(chuàng)建分為:
New消息
Message.obtain()
Handler.obtainMessage()
而Handler.obtainMessage() 最終也是調(diào)用的 Message.obtain(Handler)脱羡,所傳參數(shù)會(huì)將Handler本身賦值給Message的Target用來處理消息
接下來分析Message.obtain()
//Message.java
private static Message sPool;
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();
}
obtain() 方法會(huì)在以 sPool作為頭結(jié)點(diǎn)的消息池(鏈表)中遍歷,如果找到,那么取出來免都,并置為非使用狀態(tài)锉罐,然后返回,如果消息池為空绕娘,則新建一個(gè)消息
- 消息池的獲取
這是一個(gè)回收的方法脓规,方法體內(nèi)將 Message 對(duì)象的各種參數(shù)清空,如果消息池的數(shù)量小于最大數(shù)量(50)的話险领,就當(dāng)前消息插入緩存池的頭結(jié)點(diǎn)中
//Message.java
private static final int MAX_POOL_SIZE = 50;
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
上方法的其中一個(gè)調(diào)用在 Looper.looperzhong 使用侨舆,調(diào)用時(shí)機(jī)是在 Handler 處理事件之后,既然是 Handler 處理后就會(huì)回收:源碼如下
// Looper.java 绢陌,省略部分代碼
loop(){
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block , 從隊(duì)列取出一個(gè)msg
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg); //Handler處理消息
...
msg.recycleUnchecked(); //回收msg
}
}
總結(jié):
所以在消息處理方中:
Handler的Callback接口中
Runable的run方法中
Handler的handlerMessage
消息處理完成后系統(tǒng)就會(huì)回收消息挨下,所以不要在消息處理方法中異步的處理消息,以為在loop方法中執(zhí)行了處理方法后下面,就執(zhí)行回收复颈。如果真要在異步中使用绩聘,那么可以創(chuàng)建一個(gè)新的 Message 對(duì)象沥割,并將值賦值過去
總而言之耗啦,因?yàn)?Handler 機(jī)制在整個(gè) Android 系統(tǒng)中使用太頻繁,所以 Android 就采用了一個(gè)緩存策略机杜。就是 Message 里面會(huì)緩存一個(gè)靜態(tài)的消息池帜讲,當(dāng)消息被處理或者移除的時(shí)候就會(huì)被回收到消息池,所以推薦使用 Message.obtain()來獲取消息對(duì)象椒拗。
-
總結(jié)流程
image
把整個(gè)Handler機(jī)制比作一個(gè)流水線的話似将,那么 Handler 就是工人,可以在不同線程傳遞 Message到傳送帶(MessageQueue)蚀苛,而傳送帶是被馬達(dá)(Looper)運(yùn)輸?shù)脑谘椋R達(dá)又是一開始就運(yùn)行了(Looper.loop()),并且只會(huì)在一開始的線程堵未,所以無論哪個(gè)工人(Handler)在哪里(任意線程)傳遞產(chǎn)品(Message)腋舌,都只會(huì)在一條傳送帶(MessageQueue)上被唯一的馬達(dá)(Looper)運(yùn)送到終點(diǎn)處理,即 Message 只會(huì)在調(diào)用 Looper.loop() 的線程被處理渗蟹。
問題總結(jié)
- Handler為什么能造成內(nèi)存泄漏
Handler本身并不會(huì)造成內(nèi)存泄漏块饺,而造成內(nèi)存泄漏的主要原因是匿名內(nèi)部類的引用,匿名內(nèi)部類的隱形的持有外部類的引用 (如果不持有引用怎么可以使用外部類的變量方法呢雌芽?)
所以當(dāng)匿名內(nèi)部類的生命周期較長(zhǎng)授艰,例如正在跑一個(gè)耗時(shí)的線程,而碰巧Activity不外類此時(shí)退出世落,需要回收淮腾,而內(nèi)部類讓然引用外部類,導(dǎo)致內(nèi)存不能回收岛心。
Handler發(fā)生內(nèi)存泄漏的原因分析
Handler持有Activity来破,Message持有Handler、Message在MessageQueue中忘古、
MessageQueue在Looper中徘禁、而ThreadLoca靜態(tài)持有Looper。因?yàn)?sThreadLocal 是方法區(qū)常量髓堪,所以不會(huì)被回收送朱,即 sThreadLocal 間接的持有了 Activity 的引用,當(dāng) Handler 發(fā)送的消息還沒有被處理完畢時(shí)干旁,比如延時(shí)消息驶沼,而 Activity 又被用戶返回了,即 onDestroy() 后争群,系統(tǒng)想要對(duì) Activity 對(duì)象進(jìn)行回收回怜,但是發(fā)現(xiàn)還有引用鏈存在,回收不了换薄,就造成了內(nèi)存泄漏
怎么防止 Handler 內(nèi)存泄漏
1玉雾、把ThreadLocal與Activity的引用鏈斷開
最簡(jiǎn)單的方法就是在 onPause()中使用 Handler 的 removeCallbacksAndMessages(null)方法清除所有消息及回調(diào)翔试。就可以把引用鏈斷開了。
Android 源碼中這種方式也很常見复旬,不在 onDestroy()里面調(diào)用主要是 onDestroy() 方法不能保證每次都能執(zhí)行到
2垦缅、第二種方法就是使用靜態(tài)類加弱引用的方式
因?yàn)殪o態(tài)類不會(huì)持有外部類的引用,所以需要傳一個(gè) Activity 過來,并且使用一個(gè)弱引用來引用 Activity 的實(shí)例驹碍,
弱引用在 gc的時(shí)候會(huì)被回收壁涎,所以也就相當(dāng)于把強(qiáng)引用鏈給斷了,自然也就沒有內(nèi)存泄漏了志秃。
Loop.loop() 為什么不會(huì)造成應(yīng)用卡死怔球?
loop() 方法是一個(gè)死循環(huán),那么肯定會(huì)占用大量的 cpu 而導(dǎo)致應(yīng)用卡頓浮还,甚至說 ANR 庞溜。
但是 Android 中即使使用大量的 Looper,也不會(huì)造成這種問題碑定,問什么呢流码?
由于這個(gè)問題涉及到的知識(shí)比較深,主要是通過 Linux 的 epoll 機(jī)制實(shí)現(xiàn)的延刘,這里需要 Linux 漫试、 jni 等知識(shí),我等菜鳥就不分析了碘赖,推薦一些相關(guān)文章:
Android中為什么主線程不會(huì)因?yàn)長(zhǎng)ooper.loop()里的死循環(huán)卡死驾荣?
https://www.zhihu.com/question/34652589
總結(jié)
1. Handler 的回調(diào)方法是在 Looper.loop()所調(diào)用的線程進(jìn)行的;
2. Handler 的創(chuàng)建需要先調(diào)用 Looper.prepare() 普泡,然后再手動(dòng)調(diào)用 loop()方法開啟循環(huán)播掷;
3. App 啟動(dòng)時(shí)會(huì)在ActivityThread.main()方法中創(chuàng)建主線程的 Looper ,并開啟循環(huán),所以主線程使用 Handler 不用調(diào)用第2點(diǎn)的邏輯撼班;
4. 延時(shí)消息并不會(huì)阻塞消息隊(duì)列歧匈;
5. 異步消息不會(huì)馬上執(zhí)行,插入隊(duì)列的方式跟同步消息一樣砰嘁,唯一的區(qū)別是當(dāng)有消息屏障時(shí)件炉,異步消息可以繼續(xù)執(zhí)行,同步消息則不行矮湘;
6. Callback.handleMessage() 的優(yōu)先級(jí)比 Handler.handleMessage()要高*
7. Handler.post(Runnable)傳遞的 Runnale 對(duì)象并不會(huì)在新的線程執(zhí)行斟冕;
8. Message 的創(chuàng)建推薦使用 Message.obtain() 來獲取,內(nèi)部采用緩存消息池實(shí)現(xiàn)缅阳;
9. 不要在 handleMessage()中對(duì)消息進(jìn)行異步處理磕蛇;
10. 可以通過removeCallbacksAndMessages(null)或者靜態(tài)類加弱引用的方式防止內(nèi)存泄漏;
11. Looper.loop()不會(huì)造成應(yīng)用卡死,里面使用了 Linux 的 epoll 機(jī)制秀撇。