使用Bundle
四大组件中的三大组件(Activity、Service、BoardcastReceiver)都支持在Intent中传递Bundle数据。Bundle实现了Parcelable接口,可以很方便地在不同进程间传输。
我们可以在Bundle附加要传输给其他进程的信息并通过Intent发送给其他进程。注意的是传输的数据必须是可以被序列化的,例如基本类型、实现了Serializable或Parcelable接口的对象以及一些Android支持的特殊对象。
使用文件共享
两个进程通过读或写同一个文件来交换数据。除了可以交换文本信息,还可以序列化一个对象到文件并在另一个进程中反序列化这个对象。
但是这种方式在并发的时候可能会出问题。所以文件共享适合在并发不高的进程间通信,且要处理好并发问题。
使用Messenger(不是Message)
Messenger是一种轻量级的IPC方案,它的底层实现是AIDL。Messenger对象可以在不同进程中传递,通过在Messenger中放入需要传递的数据,就可以进行简单的跨进程通信。
简单例子
假设有两个进程,一个客户端进程和一个服务端进程。项目结构如下:
其中MainActivity运行在客户端进程,而MessengerService运行在服务端进程。1
2
3<service
android:name=".MessengerService"
android:process=":remote"/>
客户端向服务端发送一条消息
客户端先绑定服务端的Service1
2Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
其中ServiceConnection对象的创建如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
Messenger messenger = new Messenger(service);
//创建一个Message并设置其what值为Constant.MSG_FROM_CLIENT
Message message = Message.obtain(null, Constant.MSG_FROM_CLIENT);
//通过给Message设置Bundle来携带传输的数据
Bundle bundle = new Bundle();
bundle.putString(Constant.KEY_MSG, "One Msg from client.");
message.setData(bundle);
//通过Messenger发送Message
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName name) {
}
};
客户端绑定服务端的Service后:
- 根据服务端返回的IBinder对象创建一个Messenger
- 创建一个Message来携带要传输的消息
- 通过Messenger将Message发送给服务端
服务端的实现如下: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
30public class MessengerService extends Service {
public static final String TAG = "fzh";
//通过Handler来创建Messenger对象,Messenger将其他
// 进程(客户端)发来的消息传递给Handler来处理
private final Messenger mMessenger = new Messenger(new MessengerHandler());
//Handler处理其他进程发来的消息
//这里将消息打印出来
static class MessengerHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case Constant.MSG_FROM_CLIENT:
Log.d(TAG, "MessengerService: " + msg.getData()
.getString(Constant.KEY_MSG));
break;
default:
break;
}
}
}
public IBinder onBind(Intent intent) {
//返回这个Messenger对象对应的底层Binder
return mMessenger.getBinder();
}
}
- 服务端先创建一个Handler来处理其他进程发来的message
- 通过刚才的Handler来创建Messenger对象,Messenger将其他进程传来的message交给这个Handler来处理
- 在onBind方法中返回这个Messenger对象对应的底层Binder,服务端和客户端就是通过这个Binder联系起来
最后运行程序,打印结果如下:
可以看到,远程的服务端收到了消息。
服务端回应客户端
我们已经知道客户端如何发送消息给跨进程的服务端,现在来看下服务端在收到消息后,怎样回应客户端。
客户端先创建一个Messenger,用于接收服务端的回应,这个Messenger也是通过Handler来创建,最终在Handler中接收服务端的回应。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());
private static class MessengerHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case Constant.MSG_FROM_SERVICE:
Log.d(TAG, "Receive message from service: " + msg.getData()
.getString(Constant.KEY_REPLY_MSG));
break;
default:
break;
}
}
}
然后将发送给服务端的message的replyTo参数设置为刚才创建的Messenger,这样就可以将这个Messenger发送给服务端1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
//...
message.replyTo = mGetReplyMessenger;
//通过Messenger发送Message
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName name) {
}
};
服务端在接收完消息后,通过message的reply参数获得了客户端的Messenger。然后就可以通过这个Messenger来回应客户端,具体实现如下: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
27private static class MessengerHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case Constant.MSG_FROM_CLIENT:
Log.d(TAG, "MessengerService: " + msg.getData()
.getString(Constant.KEY_MSG));
//服务端通过message的replyTo参数回应客户端
Messenger messenger = msg.replyTo;
//回应给客户端的message
Message replyMessage = Message.obtain(null, Constant.MSG_FROM_SERVICE);
Bundle bundle = new Bundle();
bundle.putString(Constant.KEY_REPLY_MSG, "已收到消息");
replyMessage.setData(bundle);
//发送回应消息
try {
messenger.send(replyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
}
运行程序,打印结果如下:
可以看到,客户端收到了服务端的回应。
小结
- 客户端向服务端发送消息的流程:客户端先绑定服务端的Service,绑定成功后,用服务端返回的IBinder对象创建一个Messenger,并用这个Messenger传递message给服务端。服务端收到message后就交给对应的Handler来处理。
- 服务端回应客户端的流程:客户端先创建一个Messenger,然后在传递message给服务端时,将这个Messenger赋给message的replyTo参数。服务端在收到消息后,通过message的replyTo参数得到客户端的Messenger,服务端的回应消息就可以通过这个Messenger发送的message传递过去,客户端就在这个Messenger对应的Handler中处理服务端回应的message。
Messenger的不足
- Messenger是以串行的方式处理消息,也就是说即使有大量的消息同时发生到服务端,服务端也只能一个个处理。所以如果有大量的并发请求,就不适合用Messenger了。
- Messenger只能用于传递消息,不能跨进程调用方法。
参考
- 《Android 开发艺术探索》