跨進程通信之Messenger
1.簡介
Messenger,顧名思義即為信使,通過它可以在不同進程中傳遞Message對象,通過在Message中放入我們需要的入局,就可以輕松實現數據的跨進程傳遞了。Messenger是一種輕量級的IPC方案,其底層實現是AIDL。
Messenger的使用方法很簡單,它對AIDL進程了封裝,並且由於它一次只處理一個請求,因此在服務端我們不需要考慮同步的問題。
2.實現跨進程通信
1)服務端進程
首先我們需要在服務端創建一個Service來處理客戶端的連接請求,同時創建一個Handler並通過它來創建一個Messenger對象。然後在Service的onBind方法中返回這Messenger對象底層的Binder即可。
2)客戶端進程
客戶端進程中,首先需要綁定服務端的Service,綁定成功後用服務端返回的IBinder對象創建一個Messenger,並通過這個Messenger對象向服務端發送Message。此外,如果需要服務端響應客戶端,我們就需要像服務端那樣創建一個Handler並創建一個新的Messenger,並把這個Messenger對象通過Message的replyTo參數傳遞給服務器,服務器就可以通過這個replyTo參數回應客戶端了。
Messenger由於是在AIDL上進行了封裝,其使用過程相對比較簡單,下面的示例實現了客戶端發送消息給服務端,服務端會根據客戶端發送的消息予以回復並將回復的結果顯示在客戶端上。
3)下面直接貼上client和service的代碼,最後附上運行結果。
Client:package com.pignet.messengerdemo2;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends AppCompatActivity { private static TextView tvMsgFromService; Button btnSend; EditText etClient; private Messenger mService; private Messenger mGetReplyFromService =new Messenger(new MessengerHandler()); private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch (msg.what){ case 1: tvMsgFromService.setText(msg.getData().getString("reply")); break; } super.handleMessage(msg); } } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService=new Messenger(service); } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnSend= (Button) findViewById(R.id.btn_send); etClient= (EditText) findViewById(R.id.et_client); tvMsgFromService = (TextView) findViewById(R.id.tv_msg_from_service); Intent intent= new Intent(MainActivity.this,MessengerService.class); bindService(intent,mConnection, Context.BIND_AUTO_CREATE); btnSend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String msgFromClient; Message msg = Message.obtain(null,0); Bundle data = new Bundle(); if((msgFromClient=String.valueOf(etClient.getText()))==null){ Toast.makeText(MainActivity.this,"The Message is null",Toast.LENGTH_SHORT).show(); }else{ data.putString("msg", msgFromClient); msg.setData(data); msg.replyTo= mGetReplyFromService; try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } } }); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); } }
Service:
package com.pignet.messengerdemo2;import android.app.Service;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.support.annotation.Nullable;import android.util.Log;/** * Created by DB on 2017/7/2. */public class MessengerService extends Service { private static final String TAG="MessengerService"; private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch (msg.what){ case 0: Log.i(TAG, "receive msg from client: "+msg.getData().getString("msg")); Messenger mService = msg.replyTo; Message replyMessage = Message.obtain(null,1); Bundle bundle = new Bundle(); bundle.putString("reply","您的信息"+msg.getData().getString("msg")+"已收到,稍後會有回復"); replyMessage.setData(bundle); try{ mService.send(replyMessage); } catch (RemoteException e) { e.printStackTrace(); } } super.handleMessage(msg); } } private final Messenger mMessenger = new Messenger(new MessengerHandler()); @Nullable @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } }
這裏為了模擬不同應用間的跨進程通信,將Service類運行在了與Client不同的進程中,這樣就可以實現和不同應用間通信一樣的效果。
所以我們需要在manifests文件中加入:
<service android:name=".MessengerService" android:process=":romote"></service>
運行結果如下
3.Messenger源碼淺析:
進入到Messenger源碼後,查看它的結構
Messenger類有兩個構造函數,分別是可以用Handler和IBinder實現,這也是我們之前實現跨進程中通信中實例化Messenger類中已經用到的兩種構造函數。
public Messenger(Handler target) { mTarget = target.getIMessenger(); }
public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }
因為之前提到過Messenger的底層實現是AIDL,所以這邊我看這個IMessage和那個IBookManager有的類似,點開後發現確實如此
public interface IMessenger extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements android.os.IMessenger { private static final java.lang.String DESCRIPTOR = "android.os.IMessenger"; public Stub() { this.attachInterface(this, DESCRIPTOR); } public static android.os.IMessenger asInterface(...} public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {...} private static class Proxy implements android.os.IMessenger {...} public void send(android.os.Message msg) throws android.os.RemoteException; }
之前我們為BookManager類定義的方法是一個addBook和getBookList,而這邊我們發現Messenger對AIDL的封裝中加入的是一個send方法。
那這個方法是在哪裏實現的呢。
private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } }
它是在Handler類中的MessengerImpl方法中得到實現的,這也就可以解釋我們發送的message可以在Handler的handleMessage中出現了。
最後我們再回到Messenger類中看看Messenger的另一個重要方法:
public void send(Message message) throws RemoteException { mTarget.send(message); }
這裏我們就可以串聯起來了,Messenger類通過傳入Handler或是IBinder來獲得IMessenger的實例,然後調用send方法實際是在遠程調用IMessenger的send方法。
這裏我們就差不多把Messenger的機制理清了。
最後附上剛才實現的例子的一個簡圖:
跨進程通信之Messenger