写在前面:
本文摘自《Android开发艺术探索》
什么是Messenger?
Messenger译为“信使”,通过它可以在不同进程中传递Message对象。Messenger是一种轻量级的IPC方案,底层是实现AIDL,因其对AIDL进行了封装,所以其使用方法简单,我们可以更简便地进行进程间通信。同时,由于Messenger一次处理一个请求,因此在服务器端我们不用考虑线程同步的问题,因为服务器中不存在并发执行的情形。
Messenger的两个构造方法:
/** * Create a new Messenger pointing to the given Handler. Any Message * objects sent through this Messenger will appear in the Handler as if * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had * been called directly. * * @param target The Handler that will receive sent messages. */ public Messenger(Handler target) { mTarget = target.getIMessenger(); }
笔者查看的是Android API Platform 23源码文档,在该版本文档中未找到此第二种构造方法。
public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }
Messenger的实现分为服务器和客户端两个步骤;
1. 服务端进程
首先,我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的Binder即可。
2. 客户端进程
首先要绑定服务端的Service,绑定成功后用服务端返回的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送消息了,发消息类型为Message对象。如果需要服务端能够回应客户端,就和服务端一样,我们还要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replyTo参数就可以回应客户端。
实例:服务端接收客户端中发送的消息
服务端代码:
public class MessengerService extends Service { private static final String TAG = "MessengerService"; private static class MessengerHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MyConstants.MSG_FROM_CLIENT: Log.i(TAG, "receive msg from Client:" + msg.getData().getString("msg")); break; default: super.handleMessage(msg); } } } private final Messenger mMessenger = new Messenger(new MessengerHandler()); @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } }Messenger的作用是将客户端发送的消息传递给MessengerHandler。
注册service,让其运行在独立的进程中:
<service android:name="com.example.messenger.MessengerServce" android:process=":remote" >
public class MessengerActivity extends Activity { private static final String TAG = "MessengerActivity"; private Messenger mService; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = new Messenger(service); Message msg = Message.obtain(null, MyConstants.MSG_FROM_CLIENT); Bundle data = new Bundle(); data.putString("msg", "hello, this is client"); msg.setData(data); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_messenger); Intent intent = new Intent(this, MessengerService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); } }
关于Message
Message中所使用的载体有:what、arg1、arg2、Bundle以及replyTo。
Android 2.2以前object字段不支持挂进程传输传输;
Android 2.2以后,仅仅是系统提供的实现了Parcelable接口的对象才能通过它来传输。
这意味着我们自定义的Parcelable对象是无法通过object字段来传输的。
不过我们可以将我们自定义的序列化对象先放入Bundle中,然后将Bundle放入Message中进行传递。
在上述实例的基础上,我们添加服务端的回复功能,类似于我们给朋友发送电子邮件,发送成功后,对方的邮件会自动回复“您的邮件已经发送成功!”。
首先我们在原来服务端代码中做简单修改:
private static class MessengerHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MyConstants.MSG_FROM_CLIENT: Log.i(TAG, "receive msg from Client:" + msg.getData().getString("msg")); Messenger client = msg.replyTo; Message replyMessage = Message.obtain(null, MyConstants.MSG_FROM_SERVICE); Bundle bundle = new Bundle(); bundle.putString("reply", "嗯,你的消息我已经收到,稍候会回复你。"); replyMessage.setData(bundle); try { client.send(replyMessage); } catch (RemoteException e) { e.printStackTrace(); } break; default: super.handleMessage(msg); } } }
private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler()); private static class MessengerHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MyConstants.MSG_FROM_SERVICE: Log.i(TAG, "receive msg from Service:" + msg.getData().getString("reply")); break; default: super.handleMessage(msg); } } }
mService = new Messenger(service); Message msg = Message.obtain(null, MyConstants.MSG_FROM_CLIENT); Bundle data = new Bundle(); data.putString("msg", "hello, this is client."); msg.setData(data); // 注意下面这句 msg.replyTo = mGetReplyMessenger; try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); }