一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
双向通信实现
如果服务端收到消息需要回复客户端,应该怎么实现呢?
客户端也需要创建一个Messenger对象,接着创建一个对应的处理Handler对象,最后在onServiceConnected方法中,把Messenger对象赋值给message.replyTo,通过mService.send(message)方法发送给服务端,服务端可以通过replyTo的messenger对象给客户端发消息,从而完成双向通信,实现如下:
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取服务端关联的Messenger对象
Messenger mService=new Messenger(service);
//创建Message对象
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString("client","hello");
message.setData(bundle);
//在message中添加一个回复mReplyMessenger对象,server端可通过此来给client发消息
message.replyTo = mReplyMessenger;
try {
mService.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
private ReplyHandler mReplyHandler = new ReplyHandler();
private Messenger mReplyMessenger = new Messenger(mGetReplyHandler);
public static class ReplyHandler extends Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String serviceMsg = bundle.getString("server");
Log.i(TAG, "来自服务端的回复:"+serviceMsg);
}
}
服务端在AndroidManifest.xml中对service进行配置:
<service android:name=".model.MyService"
android:exported="true"
<intent-filter>
<action android:name="com.hly.learn.server.action" />
</intent-filter>
</service>
其实Messenger底层也是AIDL。客户端和服务端通讯,就是普通的AIDL,客户端实例化Stub之后,通过Stub的send方法把消息发到服务端。服务端和客户端通讯:服务端通过解析message的replyto,获得客户端的Stub,然后通过send方法发送到客户端。
三.源码分析
从上面实例使用可以看到,在Service的onBind()方法中通过mMessenger.getBinder()来返回对应的IBinder,先看一下Messenger的源码实现:
a.Messenger.java
public final class Messenger implements Parcelable {
private final IMessenger mTarget;
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
public IBinder getBinder() {
return mTarget.asBinder();
}
......
......
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
}
从Messenger的源码可以看到,主要有四个方法:
- 提供给服务端的构造方法,需要传入Handler实例,在方法内部通过Handler返回IMessenger实例;
- 提供给客户端的send()方法,发送message到服务端;
- 提供给服务端在onBind()返回Binder的方法;
- 提供给客户端在onServiceConnected()内部获取Messenger实例的方法;
Messenger内部同时提供了服务端和客户端对应的方法,getBinder()是通过mTarget来返回的,mTarget是通过Handler的getIMessenger()来返回的,具体实现是在Handler内部。