_StriveG Blog

消息机制在多进程的应用

1. 前言

一般情况下,我们利用handler,是在单进程情况下,但是,在多进程的模型下,也有消息机制的身影。那就是Messenger。

2. 如何使用Messenger

2.1 Messenger 服务端

首先我们需要一个messenger,并传入一个handler。

1
private Messenger messenger = new Messenger(new MessengerHandler());

其次,我们在onBind中,用Messenger的getBinder方法返回binder对象。

1
2
3
4
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}

在这个handler的handleMessage方法中,获取客户端发送的消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case Constants.MSG_FROM_CLIENT:
Log.e(TAG, "handleMessage: " + msg.getData().getString(Constants.MSG_DATA,"") );
Messenger client = msg.replyTo;
if (client != null){
Message message = Message.obtain(null,Constants.MSG_FROM_SERVER);
Bundle bundle = new Bundle();
bundle.putString(Constants.MSG_DATA,"from server");
message.setData(bundle);
try {
client.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
default:
super.handleMessage(msg);
break;
}
}
}

最后,在配置文件中,将这个service开启process,开启另一个进程。

2.2 客户端

想要实现向服务端发送消息,只需要我们在ServiceConnection的onServiceConnected方法中,用IBinder对象,构造出一个Messenger,并用这个Messenger的send方法即可。如果我们还想服务端接收到我们的消息能返回的话,我们需要给Message设置replyTo,并且在服务端用这个对象去发送消息给客户端,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public Handler getFromServer = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case Constants.MSG_FROM_SERVER:
Log.e(TAG, "handleMessage: " + msg.getData().getString(Constants.MSG_DATA,"") );
break;
default:
super.handleMessage(msg);
break;
}
}
};
private Messenger getReplyMessenger = new Messenger(getFromServer);
public ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
messenger = new Messenger(service);
Message msg = Message.obtain(null,Constants.MSG_FROM_CLIENT);
Bundle bundle = new Bundle();
bundle.putString(Constants.MSG_DATA,"from client");
msg.setData(bundle);
msg.replyTo=getReplyMessenger;
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};

3. 简单分析

之所以我们能够通过Messenger在两个进程之间通信,一是因为Messenger和Handler内部分装来binder,并且Messenger和Message都实现了Parcelable接口,下面我们来简单的看下。

首先是Messenger的getBinder方法,这个方法返回一个binder对象。

1
2
3
public IBinder getBinder() {
return mTarget.asBinder();
}

其中,mTarget是Handler#getIMessenger返回的MessengerImpl对象。

1
2
3
4
5
6
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}

而Messenger的send方法。就是调用这里的send方法。

4. 总结

其实,Messenger就是对binder的上层封装,让我们更加简单的使用。这里就不介绍AsyncChannel了,这个类是internal包下的内容,并没有对我们开放。


最近访客