一、使用Bundle
在一個進程中使用另外一個進程的Activity,Service,Receiver,在Bunlder中附加我們需要傳輸給遠程進程的信息,然後用intent發送過去,當然,我們傳輸的數據必須能夠序列化,比如基本數據類型,實現了Parcelable接口的對象,實現了Serializable接口的對象以及一些Android支持的特殊對象(具體內容可以看下Bundler這個類,Bundler不支持的類型我們無法通過他在進程間傳遞數據)——這是一種很簡單的進程間通信方式。
二、使用文件共享
1、文件共享是一種不錯的進程間通訊的方式,兩個進程通過讀/寫同一個文件來交換數據,比如A進程把數據寫入文件,B再去讀取。2、通過文件共享的方式也是有侷限性的,如果併發讀/寫,那麼我們讀出的內容就有可能不是最新的,如果是併發寫的話那就更嚴重了。
3、SharedPreferences也屬於文件的一種,但是由於系統對它的讀/寫有一定的緩存策略,即在內存中會有一份SharedPreferences文件的緩存,因此在多進程模式下,系統對它的讀/寫就變得不可靠,當面對高併發的讀/寫訪問Sharedpreferences有很大機率會丟失數據,因此,不建議在進程間通信中使SharedPreferences。
三、使用Messenger
在不同進程中傳遞Message對象,在Message中放入我們需要傳遞的數據,就可以輕鬆地實現數據的進程間傳遞了。Messenger是一種輕量級的IPC方案,它的底層實現是AIDL。
- 服務端進程
首先,我們需要在服務端創建一個Service來處理客戶端的連接請求,同時創建一個Handler並通過它來創建一個Messenger對象,然後在Service的onBind中返回這個Messenger對象底層的Binder即可。
- 客戶端進程
客戶端進程中,首先要綁定服務端的Service,綁定成功後用服務端返回的IBinder對象創建一個Messenger,通過這個Messenger就可以向服務端發送消息了,發消息類型爲 Message對象。
如果需要服務端能夠迴應客戶端,就和服務端一樣,我們還需要創建一個Handdler並創建一個新的Messenger,並把這個Messenger對象通過Message的replyTo參數傳遞給服務端,服務端通過這個replyTo參數就可以迴應客戶端。
1、看一個簡單點的例子,這個例子中服務端無法迴應客戶端。
服務端:這是服務端的典型代碼,可以看到MessengerHandler用來處理客戶端發送的消息,並從消息中取出客戶端發來的文本信息,而mMessenger是一個Messenger對象,他和MessengerHandler相關聯,並在onBind方法中返回他裏面的IBind對象
public class MessengerService extends Service {
public static final String TAG = "MessengerService";
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 100:
Log.i(TAG,"數據:" + msg.getData());
break;
default:
super.handleMessage(msg);
}
}
}
private final Messenger mMessenger = new Messenger(new MessengerHandler());
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
客戶端如下:
public class MessengerActivity extends AppCompatActivity {
public static final String TAG = "MessengerActivity";
private Messenger mService;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service);
Message msg = Message.obtain(null,10);
Bundle data = new Bundle();
data.putString("msg","hell this is client");
msg.setData(data);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
Intent intent = new Intent(this,MessengerService.class);
bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
}
這樣運行之後就能收到發送的消息了。
通過上面的例子可以看出,在Messenger中進行數據傳遞必須將數據放入Messsage中,而Messenger和Message都實現了Parcelable接口,因此可以跨進程傳輸,簡單來說,Messebger所支持的數據類型就是Message所支持的傳輸類型。實際上,通過 Messenger來傳遞Message,Message中能使用的載體就只有what、arg1、arg2、Bundle以及replyTo。Message的另一個字段object在同一個進程中是很實用的,但是在進程間通信的時候,在Android2.2以前object字段不支持跨進程傳輸,即便是2.2以後,也僅僅是系統提供的實現了Parcelable接口的對象才能通過它來傳輸。這就意味着我們自定義的Parcelable對象是無法通過object字段來傳輸的,讀者可以試一下。非系統的Parcelable對象的確無法通過object字段來傳輸,這也導致了object字段的實用性大大降低,所幸我們還有Bundle,Bundle中 可以支持大量的數據類型。
2、有時候我們還需要能迴應客戶端,下面就介紹下:
還是採用上面的例子,但是稍微做一下修改,每當客戶端發來一條消息,服務端就會自動回覆一條“嗯,你的消息我已經收到,稍後 回覆你。”,這很類似郵箱的自動回覆功能。
首先看服務端的修改,服務端只需要修改MessengerHandler,當收到消息後,會立即回覆一條消息給客戶端
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 100:
Log.i(TAG,"數據:" + msg.getData());
Messenger messenger = msg.replyTo;
Message reply = Message.obtain(null,200);
Bundle bundle = new Bundle();
bundle.putString("reply","收到你的消息,等下回復");
try {
messenger.send(reply);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
接着來看客戶端的修改,爲了接受服務端的恢復,客戶端也需要準備一個接收消息的Messenger和handler,如下:
private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 200:
Log.i(TAG,"Service:" + msg.getData().getString("reply"));
break;
default:
super.handleMessage(msg);
}
}
}
除了上述的修改,還有關鍵的一點,當客戶端發送消息的時候,需要把接收服務端回覆的Messenger通過Message的replyTo參數傳遞給服務端,如下:
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new android.os.Messenger(service);
Message msg = Message.obtain(null,100);
Bundle data = new Bundle();
data.putString("msg","hell this is client");
//注意這句話
msg.replyTo = mGetReplyMessenger;
msg.setData(data);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
通過上述的修改,我們再次運行,就達到了自動回覆的效果了;
到這裏,我們採用Messenger進程通訊的例子就說完了,我們畫一張工作原理圖,這樣更加便於理解:
另外,