【朝花夕拾】Messenger篇——Messenger使用與源碼分析


前言

      轉載請聲明,轉自【https://www.cnblogs.com/andy-songwei/p/11774836.html】,謝謝!

      提起跨進程通信,大多數人首先會想到AIDL。我們知道,用AIDL來實現跨進程通信,需要在客戶端和服務端都添加上aidl文件,並在服務端的Service中實現aidl對應的接口。如果還需要服務端給客戶端發送信息,還需要再添加回調相關的aidl文件,以及使用RemoteCallbackList來輔助實現該功能。在我的另外一篇文章【朝花夕拾】Android性能篇之(七)Android跨進程通信篇中,就專門介紹過AIDL來實現客戶端和服務端互相通信的方式,不清楚的可以看看這篇文章的介紹。本文將介紹一下另外一種更簡單的方式——Messenger,來實現客戶端和服務端跨進程互相通信。

       本文的主要內容如下:

 

 

一、Messenger簡介

       Messenger翻譯為信使,顧名思義,就是用於傳遞信息的,通過它可以在不同進程中傳遞Message對象。在Message中放入我們需要傳遞的信息,然后通過Messenger將Message傳遞給對方,就可以輕輕松松實現跨進程數據傳遞。實際上Messenger是一種輕量級的IPC(跨進程通信)方式,它的底層仍然是實現的AIDL。它是一種基於消息的進程通信,就像子線程和UI線程發送消息那樣,Demo中服務端和客戶端使用的Handler,正好說明了這一點。

 

二、Messenger使用代碼示例

       話不多說,咱們這里看看一個完整的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 }

       對應清單文件中的注冊

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 }

  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來實現,選擇哪一種,還是需要根據實際情況來選擇。

 

五、Messenger源碼分析

       到這里,就講完了Messenger的基本使用方法,以及基本知識,但我們仍然需要分析源碼來更深入理解Messenger,不能僅停留在應用的層面。下面我們大致按照按照第4點中的“客戶端和服務端交互流程圖”中的步驟,來分析一下源碼。

 

  1、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方法的返回值源碼流程。

 

  2、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!

 

  3、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來發送數據的。

 

  4、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來發送消息。

 

結語

       由於筆者水平有限,文章中如果有描述不准確或者不妥當的地方,還請讀者不吝賜教,非常感謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM