先來看一下Messenger在跨程序通訊時的使用方法,代碼如下:
上面就是Service的代碼,分析一下其實總共做了3步:
定義了一個MessengerHandler的内部類并且實作了handleMessage的内部回調;
建立了一個Messenger的對象,在Messenger的構造函數中傳入剛剛建立的handler執行個體;
在Service的onBind方法中回調messenger的getBinder()方法;
Activity中做的工作其實也不複雜也是3步:
通過綁定Service來獲得IBinder對象;
通過IBinder對象重新構造一個Messenger;
通過Messenger的send方法來發送消息;
以上就是Messenger的使用方法。好了現在就可以根據上面的使用方法來看看Messenger内部到底是怎麼來運作的。
首先先來看看參數為Handler的Messenger的構造函數
很簡單,就是儲存傳入Handler的getIMessenger()方法傳回的東西。那接下來就去看看getIMessenger()方法傳回的是什麼東西。
也不複雜,無非就是判斷一下mMessenger是不是空然後傳回一下。那mMessenger到底是什麼呢。看看它的構造函數new MessengerImpl()代碼如下:
看到這裡相信已經摸的差不多了,這個結構就是aidl的結構。這裡猜一下應該就明白了,源碼裡面肯定有定義了一個IMessage.aidl,而且裡面還聲明了一個send的方法。而這個seng的方法在Handler裡面被實作了,具體就是通過Handler來發送一條消息。那麼可以得到結論,最後mTarget獲得的其實就是一個IMessenger.Stub的執行個體,裡面已經實作了接口中的方法(send(Message msg))
事實證明确實如此,源碼的位置:platform\frameworks\base\core\java\android\os\IMessenger.aidl
上面隻是對構造函數的源碼進行了分析,但是其實已經把Messenger的結構摸的八九不離十了;
好了既然構造函數分析的差不多了,根據流程下一步應該是通過messenger.getBinder()方法取出一個Ibinder對象通過Service來傳回給Activity。那麼接下來再來看看messenger.getBinder()方法:
很清楚,調用了IInterface(mTarget就是IMessenger.Stub的執行個體繼承了IMessenger,而IMessenger繼承了IInterface)的asBInder方法傳回了一個Binder(這裡簡單的了解其實就是傳回了它自己,因為stub内部類也繼承了Binder)。
service這邊的代碼隻有這些,那根據上面的使用方法,繼續來看Activity這邊的代碼吧。
Activity這邊也有一個構造函數,參數是一個IBinder對象,這個構造函數的源碼如下:
很清楚傳回的其實就是一個proxy類也就是一個binder驅動(不明白的可以看之前的部落格)。
然後接下來就是調用了Messenger的send方法;那繼續再來看看這個send方法的源碼是怎麼樣的。
其實就是調用了剛剛proxy的send方法吧message當參數傳進去。這裡面的邏輯其實就是通過這個proxy類中的IBinder對象來遠端調用service中已經實作的send方法。
一目了然Messenger就是一個典型的aidl的例子。
Server端就是Handler裡面實作的MessengerImpl内部類,然後在Service裡面被執行個體化了。而這個aidl也是隻有一個方法(send(Message)),就是通過目前Handler來發送一個消息。
Client端就是通過Service傳回過來的IBinder類來擷取一個proxy對象,通過proxy對象遠端調用send方法來完成通訊。
補充:如果要實作Service那邊處理完消息傳回給activity的話隻要在activity裡面也建立一個Messenger,然後把這個Messenger通過Message指派給參數message.replyTo傳過去就好了,同樣Service就可以通過這個參數裡面的Messenger來發送消息給activity通過activity裡面handler來處理消息來完成雙向通訊。
注意:這裡有一點就是如果不是跨進的的話Service和Activity都運作在主線程,那麼Service中用于處理消息的Handler裡面不能執行耗時的工作,不然會導緻ActivityUI界面卡住,因為Handler是建立在Service線程(主線程)用的是主線程的Looper。如果是跨程序的話Activity這邊的主線程就不會卡住(Service所在的線程會卡住)。因為在普通的aidl在proxy調用的時候(其實就是調用IBinder.transact方法時)會挂起目前線程是以在Service端執行耗時操作時activity的UI線程會卡住。而messenger和普通的aidl不同之處在于它又添加了一個Handler,而這個Handler是運作在Service所線上程(預設為Service所在程序的主線程)而真正的Messenger.send方法隻執行了一個Handler的sengmessage方法(這個方法是運作在底層binder的工作線程中,隻要在這個線程中不執行耗時操作調用方所在的線程就不會被挂起太久)。是以不會卡住(Service線程可能會卡住)。這一點我感覺IntentService的實作非常的相似。
本文轉自 一點點征服 部落格園部落格,原文連結http://www.cnblogs.com/ldq2016/p/8418914.html:,如需轉載請自行聯系原作者