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