一、 摘要
本文介紹Android中的IPC方式之一——Messenger。
二、 關於Messenger
SDK中如此描述:
/**
* Reference to a Handler, which others can use to send messages to it.
* This allows for the implementation of message-based communication across
* processes, by creating a Messenger pointing to a Handler in one process,
* and handing that Messenger to another process.
*
* <p>Note: the implementation underneath is just a simple wrapper around
* a {@link Binder} that is used to perform the communication. This means
* semantically you should treat it as such: this class does not impact process
* lifecycle management (you must be using some higher-level component to tell
* the system that your process needs to continue running), the connection will
* break if your process goes away for any reason, etc.</p>
*/
大意是說,引用一個可以發送message的Handler。這允許基於message實現的跨進程通信,通過Handler創建一個Messanger,傳遞message到其他進程。需要注意的是,其實現僅僅是對Binder的簡單包裝。這意味着:Messenger不應該影響進程的生命週期管理(你必須用更高級別的組件來告訴系統你的進程需要繼續執行),一旦你的進程因爲任何原因中斷,Messenger的連接也會斷開。
整理出以下幾個要點:
- 通過Handler創建一個Messanger
- Messenger基於Binder實現
- 注意你的組件的生命週期
查看API文檔,Messenger有兩個構造方法:
private final IMessenger mTarget;
/**
* Create a new Messenger pointing to the given Handler. Any Message
* objects sent through this Messenger will appear in the Handler as if
* {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
* been called directly.
*
* @param target The Handler that will receive sent messages.
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
/**
* Create a Messenger from a raw IBinder, which had previously been
* retrieved with {@link #getBinder}.
*
* @param target The IBinder this Messenger should communicate with.
*/
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
簡單地理解Messanger,顧名思義就是一個信使,客戶端和服務端之間不直接進行消息通信,而是通過信使來傳達消息。
三、 編寫一個Demo
1. 服務端
我們在Service中實現一個Messanger:
public class MessengerDemoService extends Service {
private final static int MSG_RECEIVE_FROM_CLIENT_0 = 0;
private final static int MSG_RECEIVE_FROM_CLIENT_1 = 1;
private final static int MSG_REPLY_TO_CLIENT = 2;
private final Messenger mMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_RECEIVE_FROM_CLIENT_0:
// 獲取客戶端發送的message中的數據
Bundle mBundle = msg.getData();
// TODO
break;
case MSG_RECEIVE_FROM_CLIENT_1:
// 如果我們需要向客戶端返回消息,則像這樣:
Message msgReply = Message.obtain();
msgReply.what = MSG_REPLY_TO_CLIENT;
Bundle bundle = new Bundle();
// TODO 在bundle中放入回傳數據
msgReply.setData(bundle);
try {
// msg.replyTo指向回傳客戶端的Messenger實例
msg.replyTo.send(msgReply);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
});
@Override
public IBinder onBind(Intent intent) {
/**
* 通過返回Messenger實例的binder來和Service進行綁定,
* 當客戶端向該Service發送message時,便通過binder將消息發送至Messenger實例,
* 即最終將消息分發到Messenger實例的handleMessage方法中
*/
return mMessenger.getBinder();
}
}
然後在AndroidManifest中註冊Service:
<service
android:name=".MessengerDemoService"
<!--表示允許其他應用調用我們這個Service-->
android:exported="true">
</service>
2. 客戶端
在客戶端,我們需要聲明兩個Messenger,一個用來向服務端發送消息,一個用於接收服務端返回的消息。爲什麼在客戶端不能像服務端那樣直接使用replyTo的方式來回傳呢?如果客戶端和服務端都在接收消息後回傳,兩邊可能就會一直傳來傳去,這樣沒完沒了,程序就完了!並且按照C/S架構來講,我們的兩個Messenger分別對應request和response,而服務端收到request可能會進行response,如此描述,也就明白了吧。
我們在Activity中創建這兩個Messenger實例:
public class MessengerDemoClient extends AppCompatActivity {
private final static int MSG_RECEIVE_FROM_CLIENT_0 = 0;
private final static int MSG_RECEIVE_FROM_CLIENT_1 = 1;
private final static int MSG_REPLY_TO_CLIENT = 2;
// 這是客戶端用於接收服務端返回的Messenger
private Messenger mClientMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REPLY_TO_CLIENT:
// 獲取客戶端返回的message中的數據
Bundle mBundle = msg.getData();
// TODO
break;
default:
break;
}
}
});
// 這是客戶端用於向服務端發送消息的Messenger
private Messenger mServerMessenger;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
/**
* 這裏用到了Messenger的IBinder構造方式,
* 通過綁定Service的binder,我們的Messenger實例,
* 便可以通過該binder向Service發送消息
*/
mServerMessenger = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
/**
* 我們需要在Activity創建時綁定Service,通常在onCreate中
*/
private void bindService() {
Intent intent = new Intent();
// 如果我們給Service添加了用於啓動的filter:
intent.setAction("啓動的filter");
// TODO 使用setComponent或者setPackage來指定Service所在的應用
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
private void testSending() {
Message msgSend = Message.obtain();
msgSend.what = MSG_RECEIVE_FROM_CLIENT_1;
Bundle bundle = new Bundle();
// TODO 在bundle中放入傳給服務端的數據
msgSend.setData(bundle);
// 指定我們這次發送消息的返回信息由mClientMessenger來處理
msgSend.replyTo = mClientMessenger;
try {
mServerMessenger.send(msgSend);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
最後別忘了檢查我們的Activity是否在AndroidManifest中註冊了。