1. 程式人生 > >Android-Android程序間通訊之messenger

Android-Android程序間通訊之messenger

轉自‘https://www.cnblogs.com/makaruila/p/4869912.html

平時一說程序間通訊,大家都會想到AIDL,其實messenger和AIDL作用一樣,都可以進行程序間通訊。它是基於訊息的程序間通訊,就像子執行緒和UI執行緒傳送訊息那樣,是不是很簡單,還不用去寫AIDL檔案,是不是有點小爽。哈哈。

此外,還支援記錄客戶端物件的Messenger,然後可以實現一對多的通訊;甚至作為一個轉接處,任意兩個程序都能通過服務端進行通訊。

與 AIDL 比較:

  當您需要執行 IPC 時,為您的介面使用 Messenger 要比使用 AIDL 實現更加簡單,因為 Messenger 會將所有服務呼叫排入佇列,而純粹的 AIDL 介面會同時向服務傳送多個請求,服務隨後必須應對多執行緒處理。

  對於大多數應用,服務不需要執行多執行緒處理,因此使用 Messenger 可讓服務一次處理一個呼叫。如果您的服務必須執行多執行緒處理,則應使用 AIDL 來定義介面。

接下來看下怎麼用:

服務端:

1.建立一個handler物件,並實現hanlemessage方法,用於接收來自客戶端的訊息,並作處理

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方法傳送到客戶端。有精力的可以去翻一下原始碼。