長(zhǎng)春市長(zhǎng)春網(wǎng)站建設(shè)網(wǎng)百度免費(fèi)安裝
Message中可以攜帶的信息
Message中可以攜帶的數(shù)據(jù)比較豐富,下面對(duì)一些常用的數(shù)據(jù)進(jìn)行了分析。
/*** 用戶定義的消息代碼,以便當(dāng)接受到消息是關(guān)于什么的。其中每個(gè)Hanler都有自己的命名控件,不用擔(dān)心會(huì)沖突*/ public int what;
/*** 如果你只想存很少的整形數(shù)據(jù),那么可以考慮使用arg1與arg2,* 如果需要傳輸很多數(shù)據(jù)可以使用Message中的setData(Bundle bundle)*/public int arg1;
/*** 如果你只想存很少的整形數(shù)據(jù),那么可以考慮使用arg1與arg2,* 如果需要傳輸很多數(shù)據(jù)可以使用Message中的setData(Bundle bundle)*/public int arg2;
/*** 發(fā)送給接受方的任意對(duì)象,在使用跨進(jìn)程的時(shí)候要注意obj不能為null*/public Object obj;
/*** 在使用跨進(jìn)程通信Messenger時(shí),可以確定需要誰來接收*/public Messenger replyTo;
/*** 在使用跨進(jìn)程通信Messenger時(shí),可以確定需要發(fā)消息的uid*/public int sendingUid = -1;
/*** 如果數(shù)據(jù)比較多,可以直接使用Bundle進(jìn)行數(shù)據(jù)的傳遞*/Bundle data;
創(chuàng)建消息的方式
官方建議使用Message.obtain()系列方法來獲取Message實(shí)例,因?yàn)槠銶essage實(shí)例是直接從Handler的消息池中獲取的,可以循環(huán)利用,不必另外開辟內(nèi)存空間,效率比直接使用new Message()創(chuàng)建實(shí)例要高。其中具體創(chuàng)建消息的方式,我已經(jīng)為大家分好類了。具體分類如下:
//無參數(shù)
public static Message obtain() {...}
//帶Messag參數(shù)
public static Message obtain(Message orig) {}
//帶Handler參數(shù)
public static Message obtain(Handler h) {}
public static Message obtain(Handler h, Runnable callback){}
public static Message obtain(Handler h, int what){}
public static Message obtain(Handler h, int what, Object obj){}
public static Message obtain(Handler h, int what, int arg1, int arg2){}
public static Message obtain(Handler h, int what,int arg1, int arg2, Object obj) {}
其中在Message的obtain帶參數(shù)的方法中,內(nèi)部都會(huì)調(diào)用無參的obtain()方法來獲取消息后。然后并根據(jù)其傳入的參數(shù),對(duì)Message進(jìn)行賦值。(關(guān)于具體的obtain方法會(huì)在下方消息池實(shí)現(xiàn)原理中具體描述)
消息池實(shí)現(xiàn)原理
?既然官方建議使用消息池來獲取消息,那么在了解其內(nèi)部機(jī)制之前,我們來看看Message中的消息池的設(shè)計(jì)。具體代碼如下:
private static final Object sPoolSync = new Object();//控制獲取從消息池中獲取消息。保證線程安全
private static Message sPool;//消息池
private static int sPoolSize = 0;//消息池中回收的消息數(shù)量
private static final int MAX_POOL_SIZE = 50;//消息池最大容量
// sometimes we store linked lists of these things@UnsupportedAppUsage/*package*/ Message next;public static Message obtain() {synchronized (sPoolSync) {if (sPool != null) {Message m = sPool;sPool = m.next;m.next = null;m.flags = 0; //重新標(biāo)識(shí)當(dāng)前Message沒有使用過sPoolSize--;return m;}}return new Message();//如果為空直接返回}
從中我們發(fā)現(xiàn)如果sPool如果不為null,則返回直接new一個(gè)Message返回,整個(gè)方法結(jié)束,那么sPool是什么,sPool是一個(gè)message,從源碼中我們可以發(fā)現(xiàn)sPool其實(shí)就相當(dāng)于一個(gè)頭指針,指向緩存池中第一個(gè)緩存的Message,如果sPool不為null則說明緩存池中存在空閑的Message,返回緩存池中空閑的message,然后sPool執(zhí)行下一個(gè)緩存message對(duì)象,然后將msg.next重置為0,整體代碼過下來,我們發(fā)現(xiàn)Message的緩存池其實(shí)就是用了一個(gè)數(shù)據(jù)結(jié)構(gòu)-單向鏈表。具體流程如圖:
這塊就很明顯是消息池的取出了,那么它的存是在哪里呢,全局搜sPool,我們發(fā)現(xiàn)在recycleUncheck中有實(shí)現(xiàn)
/*** Recycles a Message that may be in-use.* Used internally by the MessageQueue and Looper when disposing of queued Messages.*/@UnsupportedAppUsagevoid 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 = UID_NONE;workSourceUid = UID_NONE;when = 0;target = null;callback = null;data = null;synchronized (sPoolSync) {if (sPoolSize < MAX_POOL_SIZE) {next = sPool;sPool = this;sPoolSize++;}}}
然后這塊代碼又是在recycle中調(diào)用的
/*** Return a Message instance to the global pool.* <p>* You MUST NOT touch the Message after calling this function because it has* effectively been freed. It is an error to recycle a message that is currently* enqueued or that is in the process of being delivered to a Handler.* </p>*/public void recycle() {if (isInUse()) {if (gCheckRecycle) {throw new IllegalStateException("This message cannot be recycled because it "+ "is still in use.");}return;}recycleUnchecked();}
這塊首先判斷消息是否在使用之中,如果在使用之中,繼續(xù)判斷gCheckRecycle,gCheckRecycle的默認(rèn)值是true,如果不在使用之中,最后會(huì)走進(jìn)recycleUnchecked。
然后來分析recycleUnChecked
一開始,把這個(gè)消息所有成員賦值成最初的狀態(tài),FLAG_IN_USE的值是1一開始說了Message的flags表示這個(gè)Message有沒有在使用,1表示在池中,等待復(fù)用,0表示正在被使用。重點(diǎn)看同步鎖中的代碼。
假設(shè)全局池沒有元素時(shí),我們將第一個(gè)消息放到池中,sPool一開始是NULL,next指向了sPool,所以此時(shí)的消息的sPool和next都是NULL,然后sPool指向當(dāng)前的Message對(duì)象,最后池的數(shù)量加1。大致如下圖。
假設(shè)有來個(gè)消息m2,在走一遍同步鎖中的代碼,此時(shí)全局池的狀態(tài)如下圖所示。
其他幾個(gè)類似