利用Messenger跨进程通信
Android笔记多进程通信之利用Messenger跨进程通信,
提起跨进程通信,大多数人首先会想到AIDL,AIDL,中文名称是android接口描述语言,是android系统中用于进行跨进程通信必须了解的。其实messenger和AIDL作用一样,都可以进行进程间通讯。它是基于消息的进程间通信,通过构建Message来在客户端和服务端之间传递数据,就像Handler发送消息在子线程和UI线程发送消息那样,还不用去写AIDL文件。
Messenger翻译为信使,可以在不同进程中传递Message对象,在Message中放入我们需要传递的信息,然后通过Messenger将Message传递给对方,就可以轻轻松松实现跨进程数据传递。实际上Messenger是一种轻量级的IPC(跨进程通信)方式,它的底层仍然是实现的AIDL。
此外,还支持记录客户端对象的Messenger,然后可以实现一对多的通信;甚至作为一个转接处,任意两个进程都能通过服务端进行通信。
Messenger与AIDL的异同
相同点:
1.都与IPC的调用有关;
2.Messenger 是一种轻量级的 IPC方案,底层实现了AIDL,只是进行了封装,开发的时候不用写.aidl文件。
3.都支持实时通信;
不同点:
1. Messenger一次只能处理一个请求(串行)/AIDL一次可以处理多个请求(并行);
当您需要执行 IPC 时,为您的接口使用 Messenger 要比使用 AIDL 实现更加简单,因为 Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。
对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果您的服务必须执行多线程处理,则应使用 AIDL 来定义接口。
2. Messenger不支持RPC,只能通过message传递消息/AIDL支持RPC;
3. Messenger使用简单,轻量级,不需要创建AIDL文件/AIDL使用复杂,需要创建AIDL文件;
实现步骤:
服务端:
1.创建一个handler对象,并实现hanlemessage方法,用于接收来自客户端的消息,并作处理
2.创建一个messenger,封装handler
private final Messenger mMessaenger = new Messenger(new MessengerHandler());
3.用messenger的getBinder()方法获取一个IBinder对象,通过onBind返回给客户端
public IBinder onBind(Intent intent){
return mMessenger.getBinder();
}
客户端:
1.在activity中绑定服务
2.创建ServiceConnection并在其中使用 IBinder 将 Messenger实例化
3.使用Messenger向服务端发送消息,或需要服务器端返回消息,需要创建一个messenger,封装handler,并将这个messenger传递给服务器端。在handler中接收服务器消息。这样就实现了客户端和服务端的双向通信了。
4.解绑服务
5.服务端中在 handleMessage() 方法中接收每个 Message
![](https://img.haomeiwen.com/i3150329/1236c4111bbc2416.png)
具体实例:
服务端:
创建一个service
public class MessengerService extends Service {
private static final String TAG = "MessagerService";
/**
* 处理来自客户端的消息,并用于构建Messenger
*/
private static class MessengerHandler extends Handler {
@Override
public void handleMessage(Message message) {
switch (message.what) {
//客户端建立连接
case Constant.MESSAGE_FROM_CLIENT:
Log.e(TAG, "receive message from client:" + message.getData().getString("msg"));
//向客户端回传消息,
Message msg = Message.obtain(null, Constants.MESSAGE_FROM_SERVICE);
Bundle b = new Bundle();
b.putString("msg","hello client,I have received your connection");
msg.setData(b);
try {
//如果服务端需要回复客户端,则需要拿到客户端携带过来的Messenger 对象(即msg.replyTo),通过msg.replyTo.send方法给客户端发送信息
message.replyTo.send(msg);
} catch(RemoteException e){
e.printStackTrace();
}
break;
case Constant.MESSAGE_FROM_API1: //客户端测试接口1
Log.e(TAG, "handleMessage: receive API1: " + message.getData().getString("msg"));
//向客户端回传消息,
Message msg = Message.obtain(null, Constants.MESSAGE_TO_API1);
Bundle b = new Bundle();
b.putString("msg","hello client,I have received your API1 message!");
msg.setData(b);
try {
//如果服务端需要回复客户端,则需要拿到客户端携带过来的Messenger 对象(即msg.replyTo),通过msg.replyTo.send方法给客户端发送信息
message.replyTo.send(msg);
} catch(RemoteException e){
e.printStackTrace();
}
break;
default:
super.handleMessage(message);
break;
}
}
}
/**
* 构建Messenger对象
*/
private final Messenger mMessenger = new Messenger(new MessengerHandler());
@Nullable
@Override
public IBinder onBind(Intent intent) {
//将Messenger对象的Binder返回给客户端
return mMessenger.getBinder();
}
}
注册service,当然要设置在不同的进程
<service
android:name="com.example.service.MessengerService"
android:exported="true"
android:enabled="true"
android:process=":remote" >
<intent-filter>
<action android:name="android.intent.action.SEND_MESSENGER"/>
</intent-filter>
</service>
注意:Service在声明时必须对外开放,即android:exported="true"
客户端:
客户端是通过绑定服务端返回的binder来创建Messenger对象,并通过这个Messenger对象来向服务端发送消息。
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity ";
private Messenger mService;
private Button mButtonApi1, mButtonApi2;
private TextView mTextView;
//接收service返回的信息
private Handler mReplyHandler = new Handler(){
public void handleMessage(Message message){
switch (message.what) {
case Constant.MESSAGE_FROM_SERVICE:
mTextView.setText(message.getData().get("msg").toString());
break;
case Constant.MESSAGE_TO_API1:
mTextView.setText(message.getData().get("msg").toString());
break;
default:
super.handleMessage(message);
break;
}
}
}
private Messenger mClientMessenger= new Messenger(mReplyHandler);
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(TAG, "ServiceConnection-->" + System.currentTimeMillis());
//通过服务端返回的Binder创建Messenger
mService = new Messenger(iBinder);
//创建消息,通过Bundle传递数据
Message message = Message.obtain(null, Constants.MESSAGE_FROM_CLIENT);
Bundle bundle = new Bundle();
bundle.putString("msg", "hello service,this is client");
message.setData(bundle);
//如果需要服务器返回消息,则需要将客户端的Messenger对象传递给服务端,如果不需要返回消息,则不用加这一句。
message.replyTo = mClientMessenger;
try {
//向服务端发送消息
mService.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e(TAG, "onServiceDisconnected-->binder died");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.tv_msg);
mButtonApi1 = findViewById(R.id.btn_send);
//绑定服务
Intent intent = new Intent();
intent.setAction("android.intent.action.SEND_MESSENGER");
intent.setPackage("com.example.service");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
//测试第一个接口mButtonApi1.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
Message message = Message.obtain(null, Constant.MESSAGE_FROM_API1);
Bundle bundle = new Bundle();
bundle.putString("msg", "hello service, this is API1 send by client");
message.setData(bundle);
//将客户端的Messenger对象传递给服务端的service
message.replyTo = mClientMessenger;
try {
//向服务端发送消息
mService.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onDestroy() {
//解绑服务
unbindService(mConnection);
super.onDestroy();
}
}
总结
Message中的Bundle支持多种数据类型,replyTo字段用于传输Messager对象,以便进程间相互通信
Messager以串行的方式处理客户端发来的消息,不适合有大量并发的请求
Messager方法只能传递消息,不能跨进程调用方法