Android進程間通信之messenger

這兩天在看binder,無心間在文檔看到messenger這麼個東西,感受這個東西還挺有意思的,給你們分享一下。android

平時一說進程間通信,你們都會想到AIDL,其實messenger和AIDL做用同樣,均可以進行進程間通信。它是基於消息的進程間通訊,就像子線程和UI線程發送消息那樣,是否是很簡單,還不用去寫AIDL文件,是否是有點小爽。哈哈。多線程

此外,還支持記錄客戶端對象的Messenger,而後能夠實現一對多的通訊;甚至做爲一個轉接處,任意兩個進程都能經過服務端進行通訊。app

與 AIDL 比較:ide

  當您須要執行 IPC 時,爲您的接口使用 Messenger 要比使用 AIDL 實現更加簡單,由於 Messenger 會將全部服務調用排入隊列,而純粹的 AIDL 接口會同時向服務發送多個請求,服務隨後必須應對多線程處理。spa

  對於大多數應用,服務不須要執行多線程處理,所以使用 Messenger 可以讓服務一次處理一個調用。若是您的服務必須執行多線程處理,則應使用 AIDL 來定義接口。線程

接下來看下怎麼用:3d

服務端:code

1.建立一個handler對象,並實現hanlemessage方法,用於接收來自客戶端的消息,並做處理server

2.建立一個messenger(送信人),封裝handler 對象

3.用messenger的getBinder()方法獲取一個IBinder對象,經過onBind返回給客戶端

客戶端:

1.在activity中綁定服務

2.建立ServiceConnection並在其中使用 IBinder 將 Messenger實例化 

3.使用Messenger向服務端發送消息

4.解綁服務

5.服務端中在 handleMessage() 方法中接收每一個 Message

這樣,客戶端並無調用服務的「方法」。而客戶端傳遞的「消息」(Message 對象)是服務在其 Handler 中接收的。

上面實現的僅僅是單向通訊,即客戶端給服務端發送消息,若是我須要服務端給客戶端發送消息又該怎樣作呢?

其實,這也是很容易實現的,下面就讓咱們接着上面的步驟來實現雙向通訊吧

1.在客戶端中建立一個Handler對象,用於處理服務端發過來的消息

2.建立一個客戶端本身的messenger對象,並封裝handler。

3.將客戶端的Messenger對象賦給待發送的Message對象的replyTo字段

4.在服務端的Handler處理Message時將客戶端的Messenger解析出來,並使用客戶端的Messenger對象給客戶端發送消息

這樣就實現了客戶端和服務端的雙向通訊了。

注意:注:Service在聲明時必須對外開放,即android:exported="true"

是否是看的頭暈,忘掉吧,直接看下面。

看一個簡單的例子

 1 package com.zixue.god.myapplication;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.Handler;
 6 import android.os.IBinder;
 7 import android.os.Message;
 8 import android.os.Messenger;
 9 import android.os.RemoteException;
10 import android.widget.Toast;
11 
12 //服務端service
13 public class MyService extends Service {
14     private static final int CODE = 1;
15     public MyService() {
16     }
17     @Override
18     public IBinder onBind(Intent intent) {
19         return mMessenger.getBinder();
20     }
21 
22     //建立一個送信人,封裝handler
23     private Messenger mMessenger = new Messenger(new Handler() {
24         @Override
25         public void handleMessage(Message msg) {
26             Message toClient = Message.obtain();
27             switch (msg.what) {
28                 case CODE:
29                     //接收來自客戶端的消息,並做處理
30                     int arg = msg.arg1;
31                     Toast.makeText(getApplicationContext(),arg+"" , Toast.LENGTH_SHORT).show();
32                     toClient.arg1 = 1111111111;
33                     try {
34                         //回覆客戶端消息
35                         msg.replyTo.send(toClient);
36                     } catch (RemoteException e) {
37                         e.printStackTrace();
38                     }
39             }
40             super.handleMessage(msg);
41         }
42     });
43 }

//客戶端

 1 package com.zixue.god.fuck;
 2 
 3 import android.content.ComponentName;
 4 import android.content.Intent;
 5 import android.content.ServiceConnection;
 6 import android.os.Bundle;
 7 import android.os.Handler;
 8 import android.os.IBinder;
 9 import android.os.Message;
10 import android.os.Messenger;
11 import android.os.RemoteException;
12 import android.support.v7.app.AppCompatActivity;
13 import android.util.Log;
14 import android.view.View;
15 import android.widget.Button;
16 import android.widget.Toast;
17 
18 public class MainActivity extends AppCompatActivity {
19     private boolean mBond;
20     private Messenger serverMessenger;
21     private MyConn conn;
22 
23     @Override
24     protected void onCreate(Bundle savedInstanceState) {
25         super.onCreate(savedInstanceState);
26         setContentView(R.layout.activity_main);
27         //綁定服務
28         Intent intent = new Intent();
29         intent.setAction("com.zixue.god.myapplication.server");
30         conn = new MyConn();
31         bindService(intent, conn, BIND_AUTO_CREATE);
32         Button button = (Button) findViewById(R.id.bt);
33         button.setOnClickListener(new View.OnClickListener() {
34             @Override
35             public void onClick(View v) {
36                 Message clientMessage = Message.obtain();
37                 clientMessage.what = 1;
38                 clientMessage.arg1 = 12345;
39                 try {
40                     clientMessage.replyTo = mMessenger;
41                     serverMessenger.send(clientMessage);
42                 } catch (RemoteException e) {
43                     e.printStackTrace();
44                 }
45             }
46         });
47     }
48 
49     private class MyConn implements ServiceConnection {
50 
51         @Override
52         public void onServiceConnected(ComponentName name, IBinder service) {
53             //鏈接成功
54             serverMessenger = new Messenger(service);
55             Log.i("Main", "服務鏈接成功");
56             mBond = true;
57         }
58 
59         @Override
60         public void onServiceDisconnected(ComponentName name) {
61             serverMessenger = null;
62             mBond = false;
63         }
64     }
65     private Messenger mMessenger = new Messenger(new Handler(){
66         @Override
67         public void handleMessage(Message msg) {
68             Toast.makeText(getApplicationContext(),msg.arg1+"",Toast.LENGTH_SHORT).show();
69             super.handleMessage(msg);
70         }
71     });
72     @Override
73     protected void onDestroy() {
74         if (mBond) {
75             unbindService(conn);
76         }
77         super.onDestroy();
78     }
79 
80 }

這樣就實現了客戶端和服務端雙向通訊,是否是很簡單呢。

   其實messenger底層也是AIDL。客戶端和服務端通信,就是普通的AIDL,客戶端實例化stub以後,經過stub的send方法把消息發到服務端。服務端和客戶端通信:服務端經過解析message的replyto,得到客戶端的stub,而後經過send方法發送到客戶端。有精力的能夠去翻一下源碼。

相關文章
相關標籤/搜索