前言html
轉載請聲明,轉自【http://www.javashuo.com/article/p-ptlynjkg-e.html】,謝謝!java
提起跨進程通訊,大多數人首先會想到AIDL。咱們知道,用AIDL來實現跨進程通訊,須要在客戶端和服務端都添加上aidl文件,並在服務端的Service中實現aidl對應的接口。若是還須要服務端給客戶端發送信息,還須要再添加回調相關的aidl文件,以及使用RemoteCallbackList來輔助實現該功能。在個人另一篇文章【朝花夕拾】Android性能篇之(七)Android跨進程通訊篇中,就專門介紹過AIDL來實現客戶端和服務端互相通訊的方式,不清楚的能夠看看這篇文章的介紹。本文將介紹一下另一種更簡單的方式——Messenger,來實現客戶端和服務端跨進程互相通訊。android
本文的主要內容以下:服務器
1、Messenger簡介多線程
Messenger翻譯爲信使,顧名思義,就是用於傳遞信息的,經過它能夠在不一樣進程中傳遞Message對象。在Message中放入咱們須要傳遞的信息,而後經過Messenger將Message傳遞給對方,就能夠輕輕鬆鬆實現跨進程數據傳遞。實際上Messenger是一種輕量級的IPC(跨進程通訊)方式,它的底層仍然是實現的AIDL。它是一種基於消息的進程通訊,就像子線程和UI線程發送消息那樣,Demo中服務端和客戶端使用的Handler,正好說明了這一點。app
2、Messenger使用代碼示例ide
話很少說,我們這裏看看一個完整的Demo,來直觀感覺一下Messenger的使用。本Demo演示的功能很簡單,客戶端發送消息給服務端,服務端收到消息後再發送消息給客戶端做爲響應。源碼分析
一、服務端代碼實現post
1 public class MessengerService extends Service { 2 private static final String TAG = "Messenger-Demo"; 3 private static final int MSG_CLIENT = 0x001; 4 private static final int MSG_SERVER = 0X002; 5 private static final String KEY_CLIENT = "key_client"; 6 private static final String KEY_SERVER = "key_server"; 7 8 private final Messenger mMessenger = new Messenger(new MessageHandler()); 9 10 @Nullable 11 @Override 12 public IBinder onBind(Intent intent) { 13 return mMessenger.getBinder(); 14 } 15 16 private static class MessageHandler extends Handler { 17 @Override 18 public void handleMessage(Message msg) { 19 switch (msg.what) { 20 case MSG_CLIENT: 21 Log.d(TAG, "receive msg from Client:" + msg.getData().getString(KEY_CLIENT)); 22 Messenger messenger = msg.replyTo; 23 Message serverMsg = Message.obtain(); 24 serverMsg.what = MSG_SERVER; 25 Bundle bundle = new Bundle(); 26 bundle.putString(KEY_SERVER, "Hello Client! I am fine, thank you"); 27 serverMsg.setData(bundle); 28 try { 29 messenger.send(serverMsg); 30 } catch (RemoteException e) { 31 e.printStackTrace(); 32 } 33 break; 34 default: 35 super.handleMessage(msg); 36 } 37 } 38 } 39 }
對應清單文件中的註冊性能
1 <service 2 android:name=".MessengerService " 3 android:exported="true"/>
這裏須要注意的是第三行,該Service須要提供給其它應用調用,須要將該屬性值設置爲true。
二、客戶端代碼實現
1 public class MessengerClientActivity extends AppCompatActivity { 2 3 private static final String TAG = "Messenger-Demo"; 4 private static final int MSG_CLIENT = 0x001; 5 private static final int MSG_SERVER = 0X002; 6 private static final String KEY_CLIENT = "key_client"; 7 private static final String KEY_SERVER = "key_server"; 8 private static final String SERVER_PKGNAME = "com.example.messageserver"; 9 private static final String SERVICE_PATH = "com.example.messageserver.MessengerService"; 10 private Messenger mRemoteMessenger; 11 private Messenger mLocalMessenger = new Messenger(new MessengerClientHandler()); 12 13 @Override 14 protected void onCreate(Bundle savedInstanceState) { 15 super.onCreate(savedInstanceState); 16 setContentView(R.layout.activity_main); 17 Log.d(TAG,"onCreate"); 18 bindService(); 19 } 20 21 private void bindService() { 22 Intent intent = new Intent(); 23 ComponentName componentName = new ComponentName(SERVER_PKGNAME, SERVICE_PATH); 24 intent.setComponent(componentName); 25 bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); 26 } 27 28 private static class MessengerClientHandler extends Handler { 29 @Override 30 public void handleMessage(Message msg) { 31 switch (msg.what) { 32 case MSG_SERVER: 33 Log.d(TAG, "receive msg from Server:" + msg.getData().getString(KEY_SERVER)); 34 break; 35 default: 36 break; 37 } 38 super.handleMessage(msg); 39 } 40 } 41 42 private ServiceConnection mServiceConnection = new ServiceConnection() { 43 @Override 44 public void onServiceConnected(ComponentName name, IBinder service) { 45 mRemoteMessenger = new Messenger(service); 46 Message clientMsg = Message.obtain(); 47 clientMsg.what = MSG_CLIENT; 48 Bundle bundle = new Bundle(); 49 bundle.putString(KEY_CLIENT, "Hello,Server! How are you ?"); 50 clientMsg.setData(bundle); 51 clientMsg.replyTo = mLocalMessenger; 52 try { 53 mRemoteMessenger.send(clientMsg); 54 } catch (RemoteException e) { 55 e.printStackTrace(); 56 } 57 } 58 59 @Override 60 public void onServiceDisconnected(ComponentName name) { 61 62 } 63 }; 64 65 @Override 66 protected void onDestroy() { 67 super.onDestroy(); 68 unbindService(mServiceConnection); 69 } 70 }
三、運行
運行時先啓動服務端,再啓動客戶端,能夠看到以下log信息:
1 15185-15185/com.example.messageserver D/Messenger-Demo: receive msg from Client:Hello,Server! How are you ?
2 14269-14269/com.example.messageclient D/Messenger-Demo: receive msg from Server:Hello Client! I am fine, thank you
這樣客戶端和服務端就完成了一次互相通訊。從代碼上來看,就能感覺到,相比於直接使用AIDL方式,Messenger簡潔方便了不少。
3、Messenger的使用步驟流程圖
經過前面的Demo直觀感覺了Messenger的使用,其交互流程大體爲如下六步:
對照Demo和上圖,應該可以輕鬆理解Messenger的交互流程了。這裏須要注意的是,實際上給Server端的Handler發送消息的Messenger,是結合服務端返回的IBinder實例來生成的服務端遠程代理;給客戶端Handler發送消息的Messenger也是第4步中發送給服務端的客戶端本地Messenger, 能夠理解爲是本身的Messenger給本身的Handler在發送消息。
4、Messenger和AIDL的聯繫與區別
前面咱們說過Messager的底層仍是實現的AIDL,這是它們的聯繫。它們的區別是:
(1)Messenger使用起來比AIDL簡潔方便。
(2)AIDL的客戶端接口會同時向服務端發送多個請求,服務端須要應用多線程處理。而Messenger會將全部請求排入隊列(Handler對應的MessageQueue),讓服務器一次處理一個調用,不用處理多線程問題。大多數狀況下,服務端不須要執行多線程處理此時選擇Messenger方式更合適,而若是客戶端的請求要求服務端執行多線程處理,就應該使用AIDL來實現,選擇哪種,仍是須要根據實際狀況來選擇。
5、Messenger源碼分析
到這裏,就講完了Messenger的基本使用方法,以及基本知識,但咱們仍然須要分析源碼來更深刻理解Messenger,不能僅停留在應用的層面。下面咱們大體按照按照第4點中的「客戶端和服務端交互流程圖」中的步驟,來分析一下源碼。
一、Server端Messenger的建立以及onBinder回調方法返回值流程分析
當Client端經過bindService和Server端bind時,會回調用MessengerService中的onBind方法,並返回一個IBinder對象。
1 //============MessengerService.java=========== 2 private final Messenger mMessenger = new Messenger(new MessageHandler()); 3 public IBinder onBind(Intent intent) { 4 return mMessenger.getBinder(); 5 }
第4行的mMessenger變量,它在第2行中建立,咱們跟進到源碼中看一下它的構造方法:
1 //=============Messenger.java============ 2 private final IMessenger mTarget; 3 /** 4 * Create a new Messenger pointing to the given Handler. Any Message 5 * objects sent through this Messenger will appear in the Handler as if 6 * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had 7 * been called directly. 8 * 9 * @param target The Handler that will receive sent messages. 10 */ 11 public Messenger(Handler target) { 12 mTarget = target.getIMessenger(); 13 } 14 15 //==============Handler.java=========== 16 final IMessenger getIMessenger() { 17 synchronized (mQueue) { 18 if (mMessenger != null) { 19 return mMessenger; 20 } 21 mMessenger = new MessengerImpl(); 22 return mMessenger; 23 } 24 } 25 ...... 26 private final class MessengerImpl extends IMessenger.Stub { 27 public void send(Message msg) { 28 msg.sendingUid = Binder.getCallingUid(); 29 Handler.this.sendMessage(msg); 30 } 31 }
第3~10行的註釋對理解Messenger頗有用,這裏簡單翻譯一下:建立一個新的指向給定Handler(也就是MessengerService類中的自定義的MessengerHandler)的Messenger。當Handler.sendMessage(Message)被直接調用時,任何經過該Messenger發送的Message對象都會出如今這個Handler(即MessengerHandler)中。參數是Handler 類型的targe,它將接收發送來的message。
經過上面的源碼跟蹤,能夠發現,這裏建立的Messenger,即mMessenger變量,實際上就是MessengerImpl對象。它繼承自IMessenger.Stub,看到這裏,咱們就可以很容易聯想到AIDL了,經過AIDL的方式,Service端回調的onBind方法,返回的自定義Binder就是就是這樣寫的。若是有編譯過AIDL項目,跟進Stub後能夠看到以下內容:
1 public static abstract class Stub extends android.os.Binder implements xxx 2 //============Binder.java============ 3 public class Binder implements IBinder {...}
Stub繼承自android.os.Binder,可見MessengerImpl實際上也是一個Binder對象,而Binder是IBinder的實現類。如今咱們就搞清楚了在建立Messenger對象時所建立的mTarget,實際上就是一個Binder。(這裏講到的AIDL相關的內容,能夠參照文章開頭處提到的文章,裏面有講到AIDL編譯後生成的內容)。
再看mMessenger調用的getBinder()方法。
1 //=============MessengerService.java========= 2 3 public IBinder onBind(Intent intent) { 4 return mMessenger.getBinder(); 5 } 6 7 //============Messenger.java============= 8 /** 9 * Retrieve the IBinder that this Messenger is using to communicate with 10 * its associated Handler. 11 * 12 * @return Returns the IBinder backing this Messenger. 13 */ 14 public IBinder getBinder() { 15 return mTarget.asBinder(); 16 }
第7~13行註釋有說明:該方法用於獲取IBinder,當前Messenger(即mMessenger)正在用這個IBinder和與本身關聯的Handler進行通訊。這裏仍然須要藉助aidl生成的java接口文件中的內容(下面這個Stub在前面提到過)來理解:
1 public static abstract class Stub extends android.os.Binder implements xxx { 2 ...... 3 @Override 4 public android.os.IBinder asBinder() { 5 return this; 6 } 7 ...... 8 }
經過前面的分析,咱們已經知道了繼承鏈:MessengerImpl extends IMessenger.Stub extends android.os.Binder implements IBinder。而mTarget是MessengerImpl的實例,咱們能夠得知,mTarget.asBinder()返回的就是MessengerImpl對象(這裏不太肯定這個結論是否正確,但返回的是Stub對象是顯而易見的)。這裏再次對比AIDL實現方式中onBind方法的返回形式,其常見寫法是:return new MyBinder(),這裏的MyBinder extends Stub,這樣一對比,就和AIDL不謀而合了。
到這裏,就分析完了Server端建立Messenger,以及回調onBinder方法的返回值源碼流程。
二、Client端遠程Messenger的建立
MessengerClientActivity類的第45行,bindService成功後,會建立一個用於和Server端發送消息的遠程Messenger:
//======================MessengerClientActivity.java==================
1 public void onServiceConnected(ComponentName name, IBinder service) { 2 mRemoteMessenger = new Messenger(service); 3 ...... 4 }
這裏咱們又看到了另一種建立Messenger的方式,咱們看看源碼:
//=====================Messenger.java=================
1 /** 2 * Create a Messenger from a raw IBinder, which had previously been 3 * retrieved with {@link #getBinder}. 4 * 5 * @param target The IBinder this Messenger should communicate with. 6 */ 7 public Messenger(IBinder target) { 8 mTarget = IMessenger.Stub.asInterface(target); 9 }
咱們仍然先翻譯一下注釋:從一個原始的IBinder建立一個Messenger,該IBinder以前經過getBinder方法來獲取獲得。參數爲IBinder類型,當前Messenger應該和這個IBinder進行通訊。當咱們看到第8行的時候,是否是又彷彿看到了AIDL中客戶端建立服務端代理類呢?
結合上述代碼的分析,已經很明確地驗證了第二節中說的,Messenger的底層仍然是AIDL!
三、Client端向Server端發送消息
在MessengerClientActivity類的第53行,也就是下面的第7行,就是遠程Messenger向服務端發送消息。
//===============MessengerClientActivity.java=============
1 @Override 2 public void onServiceConnected(ComponentName name, IBinder service) { 3 mRemoteMessenger = new Messenger(service); 4 Message clientMsg = Message.obtain(); 5 ...... 6 try { 7 mRemoteMessenger.send(clientMsg); 8 } catch (RemoteException e) { 9 e.printStackTrace(); 10 } 11 }
咱們查看send的源碼:
1 //============Messenger.java=========== 2 /** 3 * Send a Message to this Messenger's Handler. 4 * 5 * @param message The Message to send. Usually retrieved through 6 * {@link Message#obtain() Message.obtain()}. 7 * 8 * @throws RemoteException Throws DeadObjectException if the target 9 * Handler no longer exists. 10 */ 11 public void send(Message message) throws RemoteException { 12 mTarget.send(message); 13 } 14 15 //=============Handler.java============ 16 private final class MessengerImpl extends IMessenger.Stub { 17 public void send(Message msg) { 18 msg.sendingUid = Binder.getCallingUid(); 19 Handler.this.sendMessage(msg); 20 } 21 }
咱們仍然先簡單看看註釋:發送Message給該Messenger的Handler(該Messenger來自於Server端,因此這裏的Handler也就是Server端自定義那個Handler)。第1點中講過,mTarget就是MessengerImpl的實例,因此第12行就是執行的第17行。第19行咱們再熟悉不過了,Handler發送Message,因此咱們這裏就很明確了,遠程Messenger的send方法,實際上就是經過Handler來發送數據的。
四、Server端向Client端發送消息
實現Server端向Client端發送數據,關鍵代碼以下:
1 //======= MessengerClientActivity======== 2 private Messenger mLocalMessenger = new Messenger(new MessengerClientHandler()); 3 @Override 4 public void onServiceConnected(ComponentName name, IBinder service) { 5 mRemoteMessenger = new Messenger(service); 6 Message clientMsg = Message.obtain(); 7 ...... 8 clientMsg.replyTo = mLocalMessenger; 9 ...... 10 try { 11 mRemoteMessenger.send(clientMsg); 12 } catch (RemoteException e) { 13 e.printStackTrace(); 14 } 15 } 16 17 //==========AidlService======== 18 Messenger messenger = msg.replyTo; 19 Message serverMsg = Message.obtain(); 20 ...... 21 try { 22 messenger.send(serverMsg); 23 } catch (RemoteException e) { 24 e.printStackTrace(); 25 }
這裏關鍵中的關鍵是第8行,和第18行。客戶端須要將本地Messenger發送給Server端,也就是第8行,其源碼以下:
1 //==========Message.java=========== 2 public Messenger replyTo;
這裏的replyTo是一個Messenger類型的,第8行就將本地Messenger裝進Message中,發送到Server端了。在Server端就會接收該Messenger,如第18行中所示。這樣,Server端就拿到了Client端的本地Messenger對象,而後就能夠經過這個Messenger給Client端發送消息了,接收者爲Client端本地Messenger關聯的Handler,這樣就實現了服務端向客戶端發送消息。
到這裏,Messenger通訊流程的源碼分析就結束了。簡單來講,Messenger原理就是封裝了AIDL,以及使用Handler來發送消息。
結語
因爲筆者水平有限,文章中若是有描述不許確或者不穩當的地方,還請讀者不吝賜教,很是感謝!