前言
在上一篇中介绍了AIDL的进阶部分,本篇则介绍下基于AIDL的Messenger的用法。Messenger翻译为"信使"。可以用来进行跨进程通信而不用我们手动的编写AIDL文件,提高了开发效率。
Messenger使用流程:客户端进程中,首先要绑定服务端的Service,绑定成功后使用服务端返回的IBinder对象即可创建一个Messenger,通过这个Messenger客户端就可以向服务端发送消息了,发送消息的类型为Message对象,如果需要服务端能够回应客户端,就和服务端一样,客户端需要创建一个Messenger对象以及一个Handler对象,并将客户端创建的Messenger对象对通过Message的replyTo参数发送给服务端,那么服务端就可以通过replyTo携带的Messenger对象回应客户端了。
举个栗子
首先定义服务端,可以看到,首先定义了一个Handler对象用来处理消息,然后使用此Handler对象初始化Messenger对象,最后在onBind中将Messenger对象转换为Binder对象返回,这样一个简单的服务端就完成了。
//RemoteService.java
public class RemoteService extends Service {
private static final class RemoteHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Log.i("IPC", "msg.what = " + msg.what);
if (msg.what == RemoteConstants.MESSAGE_FROM_CLIENT) {
Bundle data = msg.getData();
String string = data.getString("msg");
Log.i("IPC", string);
}
}
}
// 处理客户端消息的Handler
private RemoteHandler mHandler = new RemoteHandler();
// 传递消息的Messenger
private Messenger mMessenger = new Messenger(mHandler);
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
然后看看客户端的实现,首先bind远程服务,然后在onServiceConnected方法中通过第二个参数初始化Messenger,这样就将客户端与服务端连接起来了,然后通过发送一个Message给服务端,就完成了一次客户端到服务端的通信。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// 创建Messenger对象
private Messenger mMessenger;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("IPC", "remote service died");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("IPC", "onServiceConnected");
// 使用IBinder对象初始化Messenger对象
mMessenger = new Messenger(service);
// 获取一个消息对象
Message message = Message.obtain();
message.what = RemoteConstants.MESSAGE_FROM_CLIENT;
// 设置需要传递的数据
Bundle data = new Bundle();
data.putString("msg", "msg from client");
message.setData(data);
try {
mMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
public void onBind(View v) {
Intent intent = new Intent(this, RemoteService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
Log.i("IPC", "bind Remote Service");
}
@Override
protected void onDestroy() {
unbindService(mServiceConnection);
Log.i("IPC", "unbindService");
super.onDestroy();
}
}
双向通信的栗子
在本文最初部分已经介绍了,要想服务端能发送消息给客户端,需要客户端也有一个Messenger对象以及一个Handler分别用来让服务端返回数据以及处理服务端返回回来的数据,并且这个Messenger对象是通过Message的replyTo字段发送给服务端的,所以修改以后的客户端代码如下。
public class MainActivity extends Activity {
//处理服务端返回的消息
private static final class ClientHandler extends Handler {
@Override
public void handleMessage(Message msg) {
if (msg.what == RemoteConstants.MESSAGE_FROM_REMOTE) {
Bundle data = msg.getData();
String string = data.getString("msg");
Log.i("IPC", string);
}
}
}
// 处理服务端返回的消息
private ClientHandler mClientHandler = new ClientHandler();
// 获取远程服务的消息的Messenger
private Messenger mClientMessenger = new Messenger(mClientHandler);
// 创建Messenger对象
private Messenger mMessenger;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("IPC", "remote service died");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("IPC", "onServiceConnected");
// 使用IBinder对象初始化Messenger对象
mMessenger = new Messenger(service);
// 获取一个消息对象
Message message = Message.obtain();
message.what = RemoteConstants.MESSAGE_FROM_CLIENT;
// 设置需要传递的数据
Bundle data = new Bundle();
data.putString("msg", "msg from client");
message.setData(data);
//将自己的Messenger对象发送给服务端
message.replyTo = mClientMessenger;
try {
mMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
}
然后服务端在收到客户端的消息以后,通过Message对象的replyTo字段即可获取到客户端传递过来的Messenger对象。并通过这个Messenger对象发送数据给客户端。修改后的代码如下。
public class RemoteService extends Service {
private static final class RemoteHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Log.i("IPC", "msg.what = " + msg.what);
if (msg.what == RemoteConstants.MESSAGE_FROM_CLIENT) {
Bundle data = msg.getData();
String string = data.getString("msg");
Log.i("IPC", string);
// 开始回复客户端
Messenger replyTo = msg.replyTo;
if (replyTo != null) {
Message obtain = Message.obtain();
obtain.what = RemoteConstants.MESSAGE_FROM_REMOTE;
Bundle bundle = new Bundle();
bundle.putString("msg", "msg from Service");
obtain.setData(bundle);
try {
replyTo.send(obtain);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
}
// 处理客户端消息的Handler
private RemoteHandler mHandler = new RemoteHandler();
// 传递消息的Messenger
private Messenger mMessenger = new Messenger(mHandler);
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
权限认证
在上一篇中,对于AIDL的权限认证介绍了两种方法,由于Messenger是基于AIDL的,所以其中的一种方法对于Messenger也是适用的,如下。
//AndroidManifest.xml //定义需要的权限 <permission android:name="org.remote.IPC" /> //声明此权限 <uses-permission android:name="org.remote.IPC" />
然后在远程Service中进行权限认证,如下
public class RemoteService extends Service {
@Override
public IBinder onBind(Intent intent) {
int check = checkCallingOrSelfPermission("org.remote.IPC");
if (check == PackageManager.PERMISSION_DENIED) {
Log.i("IPC", "bind error");
return null;
}
return mMessenger.getBinder();
}
}
Demo地址:https://github.com/CB2Git/IPCPracticeDemo/tree/master/MessengerDemo