随筆Android IPC程序通信之——Messenger
android中用于程序通信和資料共享的方式有多種,最基本的Bundle,檔案共享,Messenger,AIDL,ContentProvider,Socket等,他們的差別和使用場景這裡就不再說了,詳情自行檢視了解了解,本文直接介紹方式之一Messenger(信使)的使用方式。
代碼為例,開始看看我們遇到的問題,模拟多程序資料同步問題
1.建立一個IPCDemo,建立一個自己的Applciation并聲明一個公用變量value
2.建立兩個Activity,在第一個MainActivity中修改Oncreate中修改 Application中value值為8
由MainActivity進入第二個頁面(服務Activity)注意此activity在Manifest中配置中添加android:process=”:remote”,目的是讓其單獨運作在一個程序中,和MainActivity不同程序。
在ServerActivity中我們同樣列印Applcation中的value;
結果如下:
3.引起的問題 我們知道一個應用中Application是一個重量級的,由系統建立的單一執行個體,其中的資料是共享的,那麼這裡我們在MainActivity中修改了value值,這個應用中的其他通路的地方應該都是修改後的值,但上面的結果卻不是這樣。
原因就在于,我們的ServerActivity配置了android:process=":remote",這會導緻ServerActivity運作在另一程序中,說白了就是,MainActivity是一個應用,ServerActivity是一個應用,既然是兩個不同應用,那麼就會有兩個不同的Application執行個體,Application會建立多次(這裡兩次),這兩個執行個體分别位于不同程序(應用中),這就是為什麼修改第一個全局值,而第二個程序中的值沒有任何影響的原因。
4.解決問題 我們如何讓第一個程序修改變量值的時候,通知另一個程序同步修改對應的值?接下來就利用本文介紹的Messenger。
Messenger 運用
messenger 其實是基于消息的程序通信方式,最基本的了解就是有用戶端,服務端如下圖:
接下來代碼介紹:
我們的MainActivity用來充當用戶端,ServerActivity充當服務端,因為兩個頁面完全運作在不同的程序中。
首先,建立一個MessengerService,并在manifest中配置成和ServerActivity中相同的程序。代碼如下:
/**
* Created by Frosty on //.
*//
public class MessengerService extends Service{
public static String TAG = MessengerService.class.getSimpleName();
public final static int FROM_CLIENT = ;//來此用戶端請求
public final static int FROM_SERVICE= ;//來此服務端請求
private Messenger msngerCurrent;//目前類使用(發送消息、接收處理消息)
@Override
public void onCreate() {
super.onCreate();
msngerCurrent = new Messenger(new MessengerHandler());
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return msngerCurrent.getBinder();
}
public static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case FROM_CLIENT:
///.處理接受消息
Log.e(TAG,"收到來自用戶端【"+msg.getData().getString("name")+"】的消息:"+msg.getData().getString("content"));
MyApplication.value = msg.getData().getInt("value");
//.拿到用戶端發送消息附帶的Messenger,用它回傳消息
Messenger msngerReply = msg.replyTo;
//封裝回傳消息
Message replyMsg = Message.obtain(null,FROM_SERVICE);
Bundle bundle = new Bundle();
bundle.putString("name","阿裡雲");
bundle.putString("content","你好,我這邊已經同步修改,值為:"+MyApplication.value);
replyMsg.setData(bundle);
try {
msngerReply.send(replyMsg);//回傳消息
}catch (Exception e){}
break;
default:break;
}
}
}
}
這裡暫時隻說明這個服務的功能,利用MessengerHandler處理發送自用戶端來的資料,通過msg.what比對。
是以我們在用戶端(MainActivity中去注冊綁定這個服務,并在修改appvalue時候發送一個消息給這個服務)
public class MainActivity extends AppCompatActivity {
private Messenger msngerCurrent;
private class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case MessengerService.FROM_SERVICE:
Log.e("MessengerService","收到來自服務端【"+msg.getData().getString("name")+"】的回應:"+msg.getData().getString("content"));
unbindService(serviceConnection);
break;
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyApplication.value = ;//此處修改值
Log.e("appvalue","MainActivity中擷取到的value:"+MyApplication.value);
/*綁定服務*/
bindRemoteService();
msngerCurrent = new Messenger(new MessengerHandler());
findViewById(R.id.btn_requestServer).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,ServerActivity.class);
startActivity(intent);
}
});
}
///服務連結狀态監聽
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Messenger messengerClient = new Messenger(service);
/*封裝消息體*/
Message msg = Message.obtain(null,MessengerService.FROM_CLIENT);//對應服務端接受碼
Bundle bundle = new Bundle();
bundle.putString("name","張山");
bundle.putString("content","我修改了我們的共享值,請你務必修改!");
bundle.putInt("value",MyApplication.value);
msg.setData(bundle);
msg.replyTo=msngerCurrent;
//發送
try{
messengerClient.send(msg);
}catch (Exception e){
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
public void bindRemoteService(){
Intent intent = new Intent(this, MessengerService.class);
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(serviceConnection);
super.onDestr
oy();
}
}
我們詳細解釋一下工作流程
- 我們首先得建立一個ServiceConnection 用于檢測服務綁定後或者斷開後的操作如下圖,綁定服務連結後,回掉調nServiceConnected方法,在這個方法中,我們構造一個用戶端Messenger
并用message封裝資料,然後用這個Messenger發送消息即可
發送消息後,MessengerService便可以接收到消息處理,修改目前程序的appvalue值,并回傳附加消息給用戶端,注意這裡回傳的Messenger,直接在擷取消息體中用msg.replyTo擷取,前提是用戶端相應的在傳過來的msg中replyTo指派Mesenger,此messenger在用戶端也用來處理服務端響應回來的資料。
5.結果 我們重新開機應用,重新列印兩個值
發現在主程序修改appvalue後,另一個程序擷取到的值也及時得到同步了。
End注意:Messenger通信,可使用它進行程序間的通信,而Messenger對Service的請求采用隊列的方式,是以它不支援多線程通信。