Android消息處理機(jī)制:十分鐘讓你明白消息處理機(jī)制

引言

????Android消息機(jī)制肯定是最被經(jīng)常提起的一個(gè)概念,通過(guò)下面的文章希望大家可以理解Message、?Handler、Looper。

1 消息處理流程

? ?在子線(xiàn)程中更新UI,先使用Handler的sendMessage去發(fā)送Message對(duì)象,然后通過(guò)Handler的handleMessage()方法中獲得剛才發(fā)送的Message對(duì)象,這就是一個(gè)消息處理流程,是常用的一種情況。

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官方建議實(shí)例化Message時(shí)使用obtain方法,而不是直接new Message。因?yàn)镸essage維護(hù)著一個(gè)對(duì)象池,使用obtain方法能夠復(fù)用之前被回收的Message,下面代碼 if 語(yǔ)句就是復(fù)用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的回收是調(diào)用了方法recycleUnchecked,可以看出來(lái)對(duì)象池有最大數(shù)量(MAX_POOL_SIZE)它的值是50,并且對(duì)象池是一個(gè)單鏈表,單鏈表的優(yōu)勢(shì)就是方便插入、刪除和節(jié)約內(nèi)存。

private static final int MAX_POOL_SIZE = 50;

void recycleUnchecked() {

? ? 省略掉部分初始化代碼……

? ? synchronized (sPoolSync) {

????????if (sPoolSize < ?MAX_POOL_SIZE) {

????????????next =sPool;

? ? ? ? ? ? sPool =this;

? ? ? ? ? ? sPoolSize++;

? ? ? ????? }

????}

}

3?Handler

? ? 為了防止內(nèi)存泄漏,將Handler聲明為靜態(tài)類(lèi)。一般情況下,通過(guò)Handler的sendMessage方法發(fā)送Message,最后調(diào)用msg.dispatchMessage(msg)回調(diào)到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構(gòu)造方法

? ?Handler有七個(gè)構(gòu)造方法,不難看出①②③最后都會(huì)調(diào)用④。然后通過(guò)?Looper.myLooper()獲取到Looper對(duì)象,再通過(guò)mLooper.mQueue獲取到MessageQueue對(duì)象,最后我們會(huì)調(diào)用sendMessage方法發(fā)送Message對(duì)象到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中獲取到該線(xiàn)程下的Looper。

public static @Nullable Looper myLooper() {

????return sThreadLocal.get();

}

? ? 構(gòu)造方法⑤⑥最終會(huì)調(diào)用⑦,它們和前面四種構(gòu)造方法不同之處在于可以指定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對(duì)象之后,通過(guò)sendMessage發(fā)送對(duì)象,不難看出最后調(diào)用了sendMessageAtTime方法,通過(guò)MessageQueue queue = mQueue取得構(gòu)造Handler時(shí)所獲得的MessageQueue對(duì)象。

??? 源碼中還有幾個(gè)發(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);

}

? ? 通過(guò)enqueueMessage方法將Message加入MessageQueue 中,閱讀源碼發(fā)現(xiàn)Handler方法發(fā)送的Message最后都要到MessageQueue中。

? ? msg.target其實(shí)就是Handler自己,它的作用是用來(lái)調(diào)用自己的dispatchMessage方法,在Looper的loop方法中會(huì)說(shuō)到。

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

????調(diào)用dispatchMessage方法時(shí)會(huì)判斷msg是否有callback,而這個(gè)callback就是Runnable,通過(guò)對(duì)post的講解你就會(huì)明白是怎么回事。

public void dispatchMessage(Message msg) {

????if (msg.callback !=null) {

????????handleCallback(msg);

? ? ?}else {

????????if (mCallback !=null) {

????????????if (mCallback.handleMessage(msg)) {

????????????????return;

? ? ? ? ? ? ?}

????????}

????????handleMessage(msg);

? ? }

}

? ? 我們經(jīng)常會(huì)用到post,這個(gè)post并非真的創(chuàng)建新線(xiàn)程,?而是將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就調(diào)用handleCallback,callback為null則調(diào)用handleMessage??梢钥丛诔鰜?lái)post中的Runnable最后會(huì)在handleCallback中執(zhí)行它的run方法,并沒(méi)有創(chuàng)建新的線(xiàn)程去執(zhí)行run。

private static void handleCallback(Message message)?

????message.callback.run();

}

4 Looper

? ? 有了Message和Handler,但是還有在一個(gè)問(wèn)題,3.1中說(shuō)到的從sThreadLocal中獲取Looper,這個(gè)Looper是誰(shuí)保存到sThreadLocal中的?其實(shí)就是Looper創(chuàng)建時(shí)保存的。

? ? 在Looper這個(gè)類(lèi)中有兩個(gè)重要的方法,分別是prepare和loop方法。prepare負(fù)責(zé)創(chuàng)建Looper,loop負(fù)責(zé)無(wú)限循環(huán)讀取消息。

4.1?prepare

? ? Looper的prepare方法可以去實(shí)例化一個(gè)Looper,通過(guò)sThreadLocal.set(new Looper(quitAllowed))這行代碼可以看出來(lái),prepare創(chuàng)建了一個(gè)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));

}

? ? 在實(shí)例化Looper時(shí)就會(huì)創(chuàng)建MessageQueue,所以MessageQueue并不需要我們手動(dòng)創(chuàng)建。通過(guò)上面的 if 語(yǔ)句可以看出,一個(gè)線(xiàn)程里只能有一個(gè)Looper,否則會(huì)拋出"Only one Looper may be created per thread",因此MessageQueue在一個(gè)線(xiàn)程中也只能有一個(gè)。

? ? 通過(guò)下面的代碼我們也可以得出另一個(gè)結(jié)論,在子線(xiàn)程中必須先調(diào)用looper.prepare才能使用handler,否則handler會(huì)無(wú)法發(fā)送消息,因?yàn)闆](méi)有MessageQueue。

private Looper(boolean quitAllowed) {

????mQueue =new MessageQueue(quitAllowed);

? ? mThread = Thread.currentThread();

}

4.2 loop

????一般在子線(xiàn)程中是這么使用loop的。先使用Looper.prepare()創(chuàng)建Looper,然后發(fā)送消息,最后再使用Looper.loop()無(wú)限循環(huán)讀取消息回調(diào)到handleMessage。

Looper.prepare();

Message message = Message.obtain();

mHandler.sendMessage(message);

Looper.loop();

????loop的源碼比較長(zhǎng),只分析關(guān)鍵點(diǎn),完整源碼請(qǐng)自行查看。 ? ?

? ? 首先通過(guò)myLooper獲取到Looper對(duì)象。

????從下面的代碼可以看出Looper不能為null不然會(huì)拋出"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方法是通過(guò)me.mQueue取得MessageQueue的。

final MessageQueue queue = me.mQueue;

? ? 那么,loop是怎么實(shí)現(xiàn)無(wú)線(xiàn)循環(huán)的呢?關(guān)鍵就在于它的for循環(huán)。

? ? 然后通過(guò)queue.next()去MessageQueue中獲取消息,接著使用msg.target.dispatchMessage(msg)去分發(fā)消息(msg.target就是前面在講Handler時(shí)說(shuō)到的Handler本身),至此一個(gè)消息處理流程就分析完了。

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);

????} ? ??

}

五 整體流程總結(jié)

圖5-1 流程圖

? ? 首先由Looper.prepare創(chuàng)建Looper,Looper會(huì)創(chuàng)建MessageQueue,因?yàn)橐粋€(gè)線(xiàn)程只有一個(gè)Looper,所以一個(gè)線(xiàn)程只有一個(gè)MessageQueue。

? ? 接著創(chuàng)建Message,創(chuàng)建Message對(duì)象使用obtain方法,而不是直接new出來(lái),因?yàn)镸essage內(nèi)部維護(hù)這一個(gè)對(duì)象池,可以復(fù)用之前已經(jīng)使用過(guò)的Message對(duì)象,如果線(xiàn)程池為null會(huì)創(chuàng)建一個(gè)新的Message(new Message)。

? ? 再接著創(chuàng)建一個(gè)Handler,調(diào)用sendMessage發(fā)送Message到MessageQueue(MessageQueue并非真正的隊(duì)列,而是一個(gè)單鏈表)。

? ? 最后調(diào)用Looper.loop循環(huán)讀取消息,并調(diào)用Handler的dispatchMessage進(jìn)行回調(diào)處理?;卣{(diào)完之后調(diào)用msg.recycleUnchecked方法將msg加入到Message維護(hù)的對(duì)象池中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容