前言
在上一篇中介绍了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