本文學習目標:
- 學會如何使用Messenger進行跨進程通訊;
- 延伸閱讀:
Android 消息處理機制:http://www.itdecent.cn/p/02962454adf7
在上一章中介紹了服務使用,服務啟動的兩種方式,startService()和bindService(),startService啟動的服務,跟啟動它的應用組件是沒有聯(lián)系的,因此不管是否跨進程,startService都是可以成功的。而在跨進程服務,bindService()會異常,在onServiceConnected方法中報類型轉(zhuǎn)換異常,說明這時候不能使用這個Binder對象進行轉(zhuǎn)換了。這時候,就需要使用Messenger了。
其實Messenger底層也是使用aidl的方式來實現(xiàn)的,只不過其使用handler來處理消息,因為handler是線程安全的,所以Messenger也是線程安全的,自然Messenger只能處理單線程的問題,如果要使用多線程就該使用aidl的方式實現(xiàn)。
其實,Messenger也是通過bindService的方式,只是需要定義不用的IBinder對象。
主要步驟:
- 服務實現(xiàn)Handler,來處理客戶端發(fā)送的消息Message;
- 根據(jù)Handler創(chuàng)建一個Messenger對象;
- 通過onBinder返回Messenger的Binder對象;
- 客戶端使用IBinder將Messenger實例化,然后通過Messenger將Message發(fā)送給服務;
public class MessengerService extends Service {
public final static String TAG = MessengerService.class.getSimpleName();
public final static int MSG_SAY_HELLO = 1;
public MessengerService() {
}
@Override
public void onCreate() {
Log.d(TAG, "onCreate");
super.onCreate();
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
/**
* 1. 定義一個Handler,用于處理客戶端發(fā)來的請求
*/
class ProcessHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case MSG_SAY_HELLO:
Log.d(TAG, "service receiver from client: say hello");
break;
default:
super.handleMessage(msg);
}
}
}
/**
* 2. 創(chuàng)建一個Messenger并傳入Handler實例對象
*/
final Messenger mMessager = new Messenger(new ProcessHandler());
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
// 3.通過onBinder返回Messenger的Binder對象
return mMessager.getBinder();
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind");
return super.onUnbind(intent);
}
}
清單定義:
<service
android:name=".MessengerService"
android:enabled="true"
android:exported="true"
android:process=":messengerSer"/>
/**
* 與服務端交互的Messender
*/
Messenger mService = null;
boolean mBound = false;
/**
* ServiceConnection代表與服務的連接,
*/
ServiceConnection cnn2 = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.d("###", "onServiceConnected");
/**
* 3. 通過服務端傳遞的IBinder對象,創(chuàng)建相應的Messenger
* 然后通過Messenger對象與服務端進行交互
*/
mService = new Messenger(iBinder);
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d("###", "onServiceDisconnected");
mService = null;
mBound = false;
}
};
// 綁定服務
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, cnn2, BIND_AUTO_CREATE);
// 解綁服務
unbindService(cnn2);
mBound = false;
// 發(fā)送消息
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO);
try {
// 4. 通過Messenger發(fā)送消息
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
流程圖:

流程圖
效果:

image.png
此時,解決了客戶端往服務發(fā)送消息。如果客戶端需要接收服務的消息呢?
我們需要在客戶端定義一個Messenger和Handler,然后發(fā)送消息的時候傳遞這個Messenger。
/**
* 定義客戶端的Messenger和Handler
*/
Messenger repo = new Messenger(new ClientHandler());
class ClientHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case MessengerService.MSG_REPO_SAY_HELLO:
Log.d("####", "client receive from server say hello");
break;
default:
super.handleMessage(msg);
}
}
}
發(fā)送消息的時候,設(shè)置replyTo
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO);
msg.replyTo = repo; // 傳遞Messenger
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
服務在處理Message時候,取出客戶端的Messenger,然后發(fā)送消息
class ProcessHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case MSG_SAY_HELLO:
Log.d(TAG, "service receiver from client: say hello");
Messenger repo = msg.replyTo; // 獲取客戶端Messenger
Message rmsg = Message.obtain(null, MSG_REPO_SAY_HELLO);
try {
// 發(fā)送消息
repo.send(rmsg);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
效果:
服務:

服務收到消息
客戶端:

客戶端收到消息