Messenger可以翻译为信使,通过它可以在不同的进程中传递Message对象,在Message中放入我们需要传递的数据,
这样就可以轻松的实现进程间通信了
名称 | 优点 | 缺点 | 使用场景 |
---|---|---|---|
Bundle | 简单易用 | 只能传输Bundle支持的数据类型 | 四大组件间的进程间通信 |
文件共享 | 简单易用 | 不适合高并发场景,并且无法做到进程将即时通信 | 无并发访问情形,交换简单的数据实时性不高的场景 |
AIDL | 功能强大,支持一对多并发通信,支持实时通信 | 使用稍复杂。需要处理好线程同步 | 一对多通信且有RPC需求 |
Messenger | 功能一般,支持一对多串行通信,支持实时通信 | 不能很好处理高并发情形,不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型 | 低并发的一对多通信,无RPC需求,或者无需要返回结果的RPC需求 |
ContentProvider | 在数据资源访问方面功能强大,支持一对多并发数据共享,可通过Call方法扩展其他操作 | 可以理解为受约束的AIDL,主要提供数据源的CRUD操作 | 一对多的进程间的数据共享 |
Socket | 功能强大,可以通过网络传输字节流,支持一对多并发实时通信 | 实现细节稍微有点繁琐,不支持直接的RPC | 网络数据交换 |
public class RemoteService extends Service {
@SuppressLint("HandlerLeak")
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
String key = msg.getData().getString("key");
Log.e("TAG",key);
Toast.makeText(RemoteService.this, key, Toast.LENGTH_SHORT).show();
}
};
private Messenger messenger = new Messenger(handler);
@Nullable
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
AndroidManifest.xml配置这个服务(在一个新的进程中运行)
<service
android:name=".RemoteService"
android:process=":remote" />
服务端创建一个Handler并通过它来创建一个Messenger对象,然后在Service中onBind函数中返回Messenger对象底层的Binder即可;如果客户端发送消息过来了在handler中就可以接收到
private Messenger messenger;
//绑定远程服务
Intent intent = new Intent(this, RemoteService.class);
bindService(intent, conn, BIND_AUTO_CREATE);
//绑定服务的回调
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
messenger = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
客户端绑定Service,绑定成功后通过服务端返回的IBinder对象创建一个Messenger对象,通过这个Messenger就可以像服务端发送消息了。发送的消息类型为Message对象,这里需要注意的是Message中能使用的载体只有what、arg1、arg2、Bundle以及replayTo。
public void sendMsg(View view) {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString("key", "客户端发来了一条消息");
msg.setData(bundle);
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
07-11 05:37:48.317 9715-9715/com.azhon.messenger:remote E/TAG: 客户端发来了一条消息
通过上面几步便可以实现客户端往服务端传输数据了,那现在在来升级下难度,当服务端收到消息时回应客户端 “我收到了消息,一会回复你!”。
@SuppressLint("HandlerLeak")
private Handler receiveHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
String key = msg.getData().getString("key");
Log.e("TAG", key);
}
};
private Messenger receiveMessenger = new Messenger(receiveHandler);
乍一看是不是跟上面写的服务端一致,你没看错就是一样的。接下来重点就是在客户端发送消息的时候我们需要将这个receiveMessenger
传递给服务端(msg.replyTo = receiveMessenger)
如下代码:
public void sendMsgReplay(View view) {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString("key", "客户端发来了一条消息");
msg.setData(bundle);
//将接收消息的Messenger传递给服务端
msg.replyTo = receiveMessenger;
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
客户端已经将接收的Messenger传递给服务端了,那服务端就只要获取到然后在向客户端发送一条消息,这样就达到了
服务端收到消息回复客户端的一个效果。
@SuppressLint("HandlerLeak")
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
String key = msg.getData().getString("key");
Log.e("TAG", key);
Toast.makeText(RemoteService.this, key, Toast.LENGTH_SHORT).show();
//回复客户端,通过msg.replyTo获取到客户端的Messenger对象
Messenger reply = msg.replyTo;
Message message = new Message();
Bundle bundle = new Bundle();
bundle.putString("key", "我收到了消息,一会回复你!");
message.setData(bundle);
try {
reply.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
在服务端收到的Message对象中通过Messenger reply = msg.replyTo
获取客户传递过来的Messenger
,然后发送消息即可
07-11 06:53:55.863 10724-10724/com.azhon.messenger:remote E/TAG: 客户端发来了一条消息
07-11 06:53:55.898 10710-10710/com.azhon.messenger E/TAG: 我收到了消息,一会回复你!