前言
在Android中实现IPC(进程间通信)的方式有很多,本文讲解如何使用Messenger进行实现。Messenger可以翻译为信使,用于跨进程传输Message对象。在Message对象中,我们可以附带其他数据,这就实现了数据的跨进程传递。简而言之,Messenger是一种轻量级的IPC方案,在它的底层封装了AIDL。
支持的数据类型
Messenger只能传递Message对象。因此,Message支持的数据类型就是Messenger支持的数据类型。Message的arg1、arg2、what字段各自可以附加一个int型数据,而obj字段可以附加一个Object对象,但是只支持系统提供的Parcelable对象。因此,传递数据的重任就落在了Bundle身上。通过Bundle,我们可以传递以下类型的数据:
- 基本数据类型
String和CharSequence- 实现
Parcelable接口的对象 - 实现
Serializable接口的对象
基本流程
服务端进程
首先我们要创建一个Service,用于提供服务。在Service中,我们需要创建一个Handler对象,用于接收客户端进程发来的数据。其次,通过这个Handler创建一个Messenger对象。在Messenger对象中封装有Binder。因此,我们在Service的onBind方法中将Messenger对应的Binder对象返回。
客户端进程
首先,我们需要绑定服务器端进程的Service,并通过绑定后返回的IBinder对象创建一个Messenger。借助这个Messenger对象,我们就可以向服务器端进程发送Message数据了。
双向通信
通过上述步骤,我们只能做到从客户端进程向服务端进程传递数据,即单向通信。如果同时还要求从服务器端进程向客户端进程传递数据,就需要在客户端进程也创建一个Handler对象,用于接收服务器端传来的数据。此外,我们要通过这个Handler创建一个Messenger对象,并通过Message的replyTo字段传递给服务器端进程。服务器端可以从传来的Message中取出这个Messenger对象,然后就可以使用它向客户端传递数据了。这样,就实现了客户端和服务器端间的双向通信。
实现单向通信
服务器端:
public class ServerService extends Service {
private static final String TAG="ServerService";
public static final int DATA_FROM_CLIENT=1;
//自定义Handler,用于接收客户端传来的数据
private static class ServerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case DATA_FROM_CLIENT:
Bundle bundle=msg.getData();
Log.v(TAG,bundle.getString(ClientActivity.KEY_HELLO_TO_SERVER));
break;
default:
break;
}
}
}
private Messenger messenger=new Messenger(new ServerHandler());
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();//返回Messenger对象底层封装的Binder
}
}
可以看到,我们在Service中定义了一个静态内部类ServerHandler。同时,我们通过以下代码创建了一个Messenger对象:
private Messenger messenger=new Messenger(new ServerHandler());
在onBind方法中,我们通过getBinder方法返回了Messenger封装的Binder对象。
return messenger.getBinder();//返回Messenger对象底层封装的Binder
这样,客户端传递的数据就可以在ServerHandler中处理了。在ServerHandler中,我们通过以下代码取出Message中的数据:
Bundle bundle=msg.getData();
bundle.getString(ClientActivity.KEY_HELLO_TO_SERVER);
同时,我们为这个Service指定一个私有进程名,这样就让这个Service运行在独立的进程中了。
<service
android:name=".ServerService"
android:process=":remote">
</service>
客户端:
public class ClientActivity extends AppCompatActivity {
public static final String KEY_HELLO_TO_SERVER="HELLO_TO_SERVER";
private Messenger serverMessenger;//来自服务器端的Messenger
private ServiceConnection serviceConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
serverMessenger=new Messenger(service);
Bundle bundle=new Bundle();
bundle.putString(KEY_HELLO_TO_SERVER,"你好,服务器~");
Message message=new Message();
message.what=ServerService.DATA_FROM_CLIENT;
message.setData(bundle);
try {
serverMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
Intent intent=new Intent(this,ServerService.class);
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);//解绑
}
}
可以看到,我们通过匿名内部类的方式创建了一个ServiceConnection对象。在它的onServiceConnected方法中,我们通过获取到的IBinder对象创建了一个Messenger,通过这个Messenger就可以向服务器端发送Message了。
serverMessenger=new Messenger(service);
具体的发送代码如下:
Bundle bundle=new Bundle();
bundle.putString(KEY_HELLO_TO_SERVER,"你好,服务器~");
Message message=new Message();
message.what=ServerService.DATA_FROM_CLIENT;
message.setData(bundle);
serverMessenger.send(message);
我们先创建了一个Bundle对象,并向其中存储了一个字符串。随后,我们创建了一个Message对象,并将前面的Bundle对象设置给Message。最后,通过ServerMessenger将Message发送出去。
需要注意的是,一定要记得在Activity的onDestroy方法中解除对Service的绑定。
unbindService(serviceConnection);//解绑
运行结果:
....../com.example.ipcdemo:remote V/ServerService: 你好,服务器~
实现双向通信
我们在上面实现了一个单向通信的例子。但是要做到从服务器端给客户端发送数据,还需要进行修改。主要改动在于客户端,我们需要提供一个Handler和Messenger。具体改动如下,在主要的新增代码前都添加了注释//Add:
服务器端:
public class ServerService extends Service {
private static final String TAG="ServerService";
public static final int DATA_FROM_CLIENT=1;
public static final String KEY_HELLO_TO_CLIENT="HELLO_TO_CLIENT";
//自定义Handler,用于接收客户端传来的数据
private static class ServerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case DATA_FROM_CLIENT:
Bundle bundle=msg.getData();
Log.v(TAG,bundle.getString(ClientActivity.KEY_HELLO_TO_SERVER));
//Add
Messenger clientMessenger=msg.replyTo;
Bundle bundleToClient=new Bundle();
bundleToClient.putString(KEY_HELLO_TO_CLIENT,
"你好,客户端。我收到你的消息了。");
Message message=new Message();
message.what=ClientActivity.DATA_FROM_SERVER;
message.setData(bundleToClient);
try {
clientMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
}
private Messenger messenger=new Messenger(new ServerHandler());
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();//返回Messenger对象底层封装的Binder
}
}
可以看到,在服务器端的主要改变是在Handler中从Message的replyTo参数中获取了客户端提供的Messenger对象。通过这个对象我们就可以向客户端发送Message了。
Messenger clientMessenger=msg.replyTo;
客户端:
public class ClientActivity extends AppCompatActivity {
private static final String TAG="ClientActivity";
public static final String KEY_HELLO_TO_SERVER="HELLO_TO_SERVER";
public static final int DATA_FROM_SERVER=0;
private Messenger serverMessenger;//来自服务器端的Messenger
private ServiceConnection serviceConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
serverMessenger=new Messenger(service);
Bundle bundle=new Bundle();
bundle.putString(KEY_HELLO_TO_SERVER,"你好,服务器~");
Message message=new Message();
message.what=ServerService.DATA_FROM_CLIENT;
message.setData(bundle);
//Add
message.replyTo=messenger;
try {
serverMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
//Add
private static class ClientHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case DATA_FROM_SERVER:
Bundle bundle=msg.getData();
Log.v(TAG,bundle.getString(ServerService.KEY_HELLO_TO_CLIENT));
break;
default:
break;
}
}
}
//Add
private Messenger messenger=new Messenger(new ClientHandler());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
Intent intent=new Intent(this,ServerService.class);
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);//解绑
}
}
可以看到,我们定义了一个静态内部类作为客户端的Handler类,并通过Handler创建了一个Messenger对象。这一过程和服务器端的做法一致。在绑定Service时,我们将这个Messenger作为Message的replyTo参数传递给了服务器端。这样,服务器端就可以获取到客户端提供的Messenger了。具体代码如下:
message.replyTo=messenger;
运行结果:
....../com.example.ipcdemo:remote V/ServerService: 你好,服务器~
....../com.example.ipcdemo V/ClientActivity: 你好,客户端。我收到你的消息了。
小结
通过以上例子,可以看出Messenger的使用是很方便的,毕竟系统已经为我们做了封装。但是,这种方式的局限性也很明显。首先,通过这种方式只能传递Message,无法实现远程方法调用(RPC)。其次,从上文的代码也可以看出Messenger的消息传递是通过Handler进行处理的,这意味着Messenger的消息是串行处理的,显然这不适合高并发的场景。如果有更高的交互要求,可以考虑使用AIDL实现IPC。具体请参考另一篇博客:
本文介绍如何使用Messenger在Android中实现进程间通信(IPC),包括单向和双向通信的实现方法及代码示例。

798

被折叠的 条评论
为什么被折叠?



