【朝花夕拾】跨進程通訊,你只知道AIDL,就OUT了
- 2019 年 11 月 1 日
- 筆記
一、前言
提起跨進程通訊,大多數人首先會想到AIDL。我們知道,用AIDL來實現跨進程通訊,需要在客戶端和服務端都添加上aidl文件,並在服務端的Service中實現aidl對應的介面。如果還需要服務端給客戶端發送資訊,還需要再添加回調相關的aidl文件,以及使用RemoteCallbackList來輔助實現該功能。在我的另外一篇文章【朝花夕拾】Android性能篇之(七)Android跨進程通訊篇中,就專門介紹過AIDL來實現客戶端和服務端互相通訊的方式,不清楚的可以看看這篇文章的介紹。本文將介紹一下另外一種更簡單的方式——Messenger,來實現客戶端和服務端跨進程互相通訊。
二、Messenger簡介
Messenger翻譯為信使,顧名思義,就是用於傳遞資訊的,通過它可以在不同進程中傳遞Message對象。在Message中放入我們需要傳遞的資訊,然後通過Messenger將Message傳遞給對方,就可以輕輕鬆鬆實現跨進程數據傳遞。實際上Messenger是一種輕量級的IPC(跨進程通訊)方式,它的底層仍然是實現的AIDL。它是一種基於消息的進程通訊,就像子執行緒和UI執行緒發送消息那樣,Demo中服務端和客戶端使用的Handler,正好說明了這一點。
三、示例程式碼演示
話不多說,咱們這裡看看一個完整的Demo,來直觀感受一下Messenger的使用。本Demo演示的功能很簡單,客戶端發送消息給服務端,服務端收到消息後再發送消息給客戶端作為響應。
1、服務端程式碼實現

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 }
View Code
對應清單文件中的註冊
1 <service 2 android:name=".MessengerService " 3 android:exported="true"/>
這裡需要注意的是第三行,該Service需要提供給其它應用調用,需要將該屬性值設置為true。
2、客戶端程式碼實現

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 }
View Code
3、運行
運行時先啟動服務端,再啟動客戶端,可以看到如下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簡潔方便了很多。
四、Messenger的使用步驟
通過前面的Demo直觀感受了Messenger的使用,其交互流程大致為一下六步:
對照Demo和上圖,應該能夠輕鬆理解Messenger的交互流程了。這裡需要注意的是,實際上給Server端的Handler發送消息的Messenger,是結合服務端返回的IBinder實例來生成的服務端遠程代理;給客戶端Handler發送消息的Messenger也是第4步中發送給服務端的客戶端本地Messenger, 可以理解為是自己的Messenger給自己的Handler在發送消息。
五、Messenger和AIDL的聯繫與區別
前面我們說過Messager的底層還是實現的AIDL,這是它們的聯繫。它們的區別是:
(1)Messenger使用起來比AIDL簡潔方便。
(2)AIDL的客戶端介面會同時向服務端發送多個請求,服務端需要應用多執行緒處理。而Messenger會將所有請求排入隊列(Handler對應的MessageQueue),讓伺服器一次處理一個調用,不用處理多執行緒問題。大多數情況下,服務端不需要執行多執行緒處理此時選擇Messenger方式更合適,而如果客戶端的請求要求服務端執行多執行緒處理,就應該使用AIDL來實現,選擇哪一種,還是需要根據實際情況來選擇。
結語
由於筆者水平有限,文章中如果有描述不準確或者不妥當的地方,還請讀者不吝賜教,非常感謝!