引言
????Android消息機制肯定是最被經(jīng)常提起的一個概念,通過下面的文章希望大家可以理解Message、?Handler、Looper。
1 消息處理流程
? ?在子線程中更新UI晾腔,先使用Handler的sendMessage去發(fā)送Message對象,然后通過Handler的handleMessage()方法中獲得剛才發(fā)送的Message對象列肢,這就是一個消息處理流程华蜒,是常用的一種情況。
new Thread(new Runnable() {
????@Override
????public void run() {
? ? ? ? ? ? Message message = Message.obtain();
? ? ? ????? mHandler.sendMessage(message);
? ????? }
}).start();
mHandler =new Handler(new Handler.Callback() {
????@Override
? ? public boolean handleMessage(Message msg) {
????????return false;
? ? }
});
2 Message
? ? Google官方建議實例化Message時使用obtain方法看彼,而不是直接new Message廊佩。因為Message維護著一個對象池囚聚,使用obtain方法能夠復用之前被回收的Message,下面代碼 if 語句就是復用Message标锄。
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();
}
? ? 而Message的回收是調用了方法recycleUnchecked顽铸,可以看出來對象池有最大數(shù)量(MAX_POOL_SIZE)它的值是50,并且對象池是一個單鏈表料皇,單鏈表的優(yōu)勢就是方便插入谓松、刪除和節(jié)約內存。
private static final int MAX_POOL_SIZE = 50;
void recycleUnchecked() {
? ? 省略掉部分初始化代碼……
? ? synchronized (sPoolSync) {
????????if (sPoolSize < ?MAX_POOL_SIZE) {
????????????next =sPool;
? ? ? ? ? ? sPool =this;
? ? ? ? ? ? sPoolSize++;
? ? ? ????? }
????}
}
3?Handler
? ? 為了防止內存泄漏践剂,將Handler聲明為靜態(tài)類鬼譬。一般情況下,通過Handler的sendMessage方法發(fā)送Message逊脯,最后調用msg.dispatchMessage(msg)回調到handleMessage方法优质。
static class MyHandler extends Handler {
? ? ? ? WeakReference mWeakReference;
? ? ? ? public MyHandler(Activity activity){
? ? ? ? ? ? mWeakReference=new WeakReference(activity);
?????????}
? ? ? ? @Override
? ? ? ? public void handleMessage(Message msg) {
? ? ? ? ? ? final Activity activity=mWeakReference.get();
? ? ? ? ? ? if(activity!=null) {
? ? ? ? ? ? ? ? ? ? //
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
3.1 Handler構造方法
? ?Handler有七個構造方法,不難看出①②③最后都會調用④军洼。然后通過?Looper.myLooper()獲取到Looper對象巩螃,再通過mLooper.mQueue獲取到MessageQueue對象,最后我們會調用sendMessage方法發(fā)送Message對象到MessageQueue中匕争。
? ① ?public Handler() { this(null, false);}
? ② ?public Handler(Callback callback) {this(callback, false);}
? ③ ?public Handler(boolean async) { this(null, async); }
? ④ ?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;
}
? ? 查看myLooper的源碼不難看出避乏,myLooper是從sThreadLocal中獲取到該線程下的Looper。
public static @Nullable Looper myLooper() {
????return sThreadLocal.get();
}
? ? 構造方法⑤⑥最終會調用⑦甘桑,它們和前面四種構造方法不同之處在于可以指定Looper淑际。
⑤ ?public Handler(Looper looper) { this(looper, null, false); }
⑥ ?public Handler(Looper looper, Callback callback) { this(looper, callback, false); }
⑦ ?public Handler(Looper looper, Callback callback, boolean async) {
????????mLooper = looper;
????????mQueue = looper.mQueue;
????????mCallback = callback;
????????mAsynchronous = async;
}
3.2?sendMessage方法
????創(chuàng)建完Handler對象之后,通過sendMessage發(fā)送對象扇住,不難看出最后調用了sendMessageAtTime方法春缕,通過MessageQueue queue = mQueue取得構造Handler時所獲得的MessageQueue對象。
??? 源碼中還有幾個發(fā)送消息的方法就不一一講解了艘蹋。
public final boolean sendMessage(Message msg){
????return sendMessageDelayed(msg, 0);
}
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);
}
? ? 通過enqueueMessage方法將Message加入MessageQueue 中锄贼,閱讀源碼發(fā)現(xiàn)Handler方法發(fā)送的Message最后都要到MessageQueue中。
? ? msg.target其實就是Handler自己女阀,它的作用是用來調用自己的dispatchMessage方法宅荤,在Looper的loop方法中會說到。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
????msg.target =this;
? ? if (mAsynchronous) {
????????msg.setAsynchronous(true);
? ? }
????return queue.enqueueMessage(msg, uptimeMillis);
}
3.3?dispatchMessage
????調用dispatchMessage方法時會判斷msg是否有callback浸策,而這個callback就是Runnable冯键,通過對post的講解你就會明白是怎么回事。
public void dispatchMessage(Message msg) {
????if (msg.callback !=null) {
????????handleCallback(msg);
? ? ?}else {
????????if (mCallback !=null) {
????????????if (mCallback.handleMessage(msg)) {
????????????????return;
? ? ? ? ? ? ?}
????????}
????????handleMessage(msg);
? ? }
}
? ? 我們經(jīng)常會用到post庸汗,這個post并非真的創(chuàng)建新線程惫确,?而是將Runnable封裝到Message中。
mHandler.post(new Runnable() {
????@Override
? ? public void run() {
????}
});
public final boolean post(Runnable r, long delayMillis)
{
????return sendMessageDelayed(getPostMessage(r), delayMillis);
}
private static Message ?getPostMessage(Runnable r) {
????Message m = Message.obtain();
? ? m.callback = r;
? ? return m;
}
? ? 閱讀dispatchMessage源碼發(fā)現(xiàn),如果callback不為null就調用handleCallback改化,callback為null則調用handleMessage掩蛤。可以看在出來post中的Runnable最后會在handleCallback中執(zhí)行它的run方法陈肛,并沒有創(chuàng)建新的線程去執(zhí)行run揍鸟。
private static void handleCallback(Message message)?
????message.callback.run();
}
4 Looper
? ? 有了Message和Handler,但是還有在一個問題句旱,3.1中說到的從sThreadLocal中獲取Looper阳藻,這個Looper是誰保存到sThreadLocal中的?其實就是Looper創(chuàng)建時保存的谈撒。
? ? 在Looper這個類中有兩個重要的方法腥泥,分別是prepare和loop方法。prepare負責創(chuàng)建Looper港华,loop負責無限循環(huán)讀取消息道川。
4.1?prepare
? ? Looper的prepare方法可以去實例化一個Looper,通過sThreadLocal.set(new Looper(quitAllowed))這行代碼可以看出來立宜,prepare創(chuàng)建了一個Looper加入到sThreadLocal中冒萄。
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));
}
? ? 在實例化Looper時就會創(chuàng)建MessageQueue,所以MessageQueue并不需要我們手動創(chuàng)建橙数。通過上面的 if 語句可以看出尊流,一個線程里只能有一個Looper,否則會拋出"Only one Looper may be created per thread"灯帮,因此MessageQueue在一個線程中也只能有一個崖技。
? ? 通過下面的代碼我們也可以得出另一個結論,在子線程中必須先調用looper.prepare才能使用handler钟哥,否則handler會無法發(fā)送消息迎献,因為沒有MessageQueue。
private Looper(boolean quitAllowed) {
????mQueue =new MessageQueue(quitAllowed);
? ? mThread = Thread.currentThread();
}
4.2 loop
????一般在子線程中是這么使用loop的腻贰。先使用Looper.prepare()創(chuàng)建Looper吁恍,然后發(fā)送消息,最后再使用Looper.loop()無限循環(huán)讀取消息回調到handleMessage播演。
Looper.prepare();
Message message = Message.obtain();
mHandler.sendMessage(message);
Looper.loop();
????loop的源碼比較長冀瓦,只分析關鍵點,完整源碼請自行查看写烤。 ? ?
? ? 首先通過myLooper獲取到Looper對象翼闽。
????從下面的代碼可以看出Looper不能為null不然會拋出"No Looper; Looper.prepare() wasn't called on this thread.",所以loop方法必須在Looper.prepare方法后使用洲炊。
final Looper me =myLooper();
? ? if (me ==null) {
????????throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
????}
public static @Nullable Looper?myLooper() {
????return sThreadLocal.get();
}
? ? ?loop方法是通過me.mQueue取得MessageQueue的感局。
final MessageQueue queue = me.mQueue;
? ? 那么尼啡,loop是怎么實現(xiàn)無線循環(huán)的呢?關鍵就在于它的for循環(huán)蓝厌。
? ? 然后通過queue.next()去MessageQueue中獲取消息玄叠,接著使用msg.target.dispatchMessage(msg)去分發(fā)消息(msg.target就是前面在講Handler時說到的Handler本身)古徒,至此一個消息處理流程就分析完了拓提。
for (;;) {
????Message msg = queue.next(); // might block
? ? if (msg ==null) {
????????// No message indicates that the message queue is quitting.
? ? ? ? return;
? ? ?}
????try {
????????msg.target.dispatchMessage(msg);
????} ? ??
}
五 整體流程總結
? ? 首先由Looper.prepare創(chuàng)建Looper,Looper會創(chuàng)建MessageQueue隧膘,因為一個線程只有一個Looper代态,所以一個線程只有一個MessageQueue。
? ? 接著創(chuàng)建Message疹吃,創(chuàng)建Message對象使用obtain方法蹦疑,而不是直接new出來,因為Message內部維護這一個對象池萨驶,可以復用之前已經(jīng)使用過的Message對象歉摧,如果線程池為null會創(chuàng)建一個新的Message(new Message)。
? ? 再接著創(chuàng)建一個Handler腔呜,調用sendMessage發(fā)送Message到MessageQueue(MessageQueue并非真正的隊列叁温,而是一個單鏈表)。
? ? 最后調用Looper.loop循環(huán)讀取消息核畴,并調用Handler的dispatchMessage進行回調處理膝但。回調完之后調用msg.recycleUnchecked方法將msg加入到Message維護的對象池中谤草。