一.Messenger简介
与AIDL进程间通信作用一样,Messenger是基于Message对象进行跨进程通信的,类似于Handler发送消息实现子线程和UI线程进行通信,此外,还支持记录客户端对象的Messenger,然后可以实现一对多的通信;甚至作为一个转接处,任意两个进程都能通过服务端进行通信。
普通的进程间通信,需要服务端自己提供AIDL接口文件,然后本地实现Stub内方法,客户端需要引入方可进行通信;
Messenger是系统提供统一的AIDL接口文件,并且由Handler来实现Stub内方法,服务端在Handler内处理即可,客户端不需要引入,直接可以通信;
二.Messenger实现流程
a.服务端实现
1.创建一个Handler对象,并实现handleMessage方法,用于接收来自客户端的消息并作处理;
2.创建一个Messenger(送信人),封装Handler;
3.用Messenger的getBinder()方法获取一个IBinder对象,通过onBind返回给客户端;
代码如下:
public class MyService extends Service {
private static final String TAG = MyService.class.getSimpleName();
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
private MessengerHandler mHandler = new MessengerHandler();
private Messenger mMessenger = new Messenger(mHandler);
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//取出客户端的消息内容
Bundle bundle = msg.getData();
String clientMsg = bundle.getString("client");
Log.i(TAG,"来自客户端的消息:"+clientMsg);
//新建一个Message对象,作为回复客户端的对象
Message message = Message.obtain();
Bundle bundle1 = new Bundle();
bundle1.putString("server","已收到消息");
message.setData(bundle1);
try {
msg.replyTo.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
服务端接受到客户端的消息,其实与线程间通信一样,也是在handleMessage方法中进行处理;
如果服务端需要回复客户端,则需要获取到客户端携带过来的Messenger对象(即msg.replyTo),通过msg.replyTo.send()给客户端发送信息。
b.客户端实现
1.绑定服务,创建ServiceConnection并在其中使用IBinder将Messenger实例化;
2.使用Messenger向服务端发送消息;
3.接收服务端发送过来的message;
4.解绑服务;
实现如下:
public class MyActivity extends Activity implements View.OnClickListener {
private static final String TAG = MyActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bindService = findViewById(R.id.bindService);
Button unBindService = findViewById(R.id.unBindService);
bindService.setOnClickListener(this);
unBindService.setOnClickListener(this);
}
public void onClick(View view) {
switch (view.getId()){
case R.id.bindService:
Intent intent = new Intent();
intent.setAction("com.hly.learn.server.action");
bindService(intent,mConnection,BIND_AUTO_CREATE);
break;
case R.id.unBindService:
unbindService(mConnection);
break;
default:
break;
}
}
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);
try {
mService.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onDestroy() {
super.onDestroy();
}
}
客户端在绑定服务之后,在ServiceConnection中通过IBinder得到Messenger对象(mService),然后用mService的send方法把Message作为形参发送给服务端。
双向通信实现
如果服务端收到消息需要回复客户端,应该怎么实现呢?
客户端也需要创建一个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进行配置:
其实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的源码可以看到,主要有四个方法:
1.提供给服务端的构造方法,需要传入Handler实例,在方法内部通过Handler返回IMessenger实例;
2.提供给客户端的send()方法,发送message到服务端;
3.提供给服务端在onBind()返回Binder的方法;
4.提供给客户端在onServiceConnected()内部获取Messenger实例的方法;
Messenger内部同时提供了服务端和客户端对应的方法,getBinder()是通过mTarget来返回的,mTarget是通过Handler的getIMessenger()来返回的,具体实现是在Handler内部,一起看一下Handler的内部对应的实现:
b.Handler.java
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
c.IMessenger.aidl
oneway interface IMessenger {
void send(in Message msg);
}
d.IMessenger.java
public interface IMessenger extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.os.IMessenger {
private static final java.lang.String DESCRIPTOR = "android.os.IMessenger";
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
........
........
@Override public android.os.IBinder asBinder() {
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code)
..........
case TRANSACTION_send: {
data.enforceInterface(DESCRIPTOR);
android.os.Message _arg0;
if ((0!=data.readInt())) {
_arg0 = android.os.Message.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.send(_arg0);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements android.os.IMessenger {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override public android.os.IBinder asBinder() {
return mRemote;
}
.........
@Override public void send(android.os.Message msg) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((msg!=null)) {
_data.writeInt(1);
msg.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_send, _data, null, android.os.IBinder.FLAG_ONEWAY);
} finally {
_data.recycle();
}
}
}
static final int TRANSACTION_send = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void send(android.os.Message msg) throws android.os.RemoteException;
}
从上面可以看到,getIMessenger()返回的是MessengerImpl实例,而MessengerImpl是继承了IMessenger.Stub,实现了send()方法来接收消息,从这里可以看到,用的是跟AIDL相同的处理;
总结一下
服务端:service的onBind()方法调用Messenger.getBinder(),最终是通过IMessenger.Stub的asBinder()返回的IBinder;
客户端:onServiceConnected()里面调用Messenger mService=new Messenger(service)来返回Messenger对象,在构造方法内部会先通过IMessenger.Stub.asInterface(target)来创建IMessenger实例mTarget;
交互:客户端在通过send()发送消息时,会通过mTarget的send()方法,经过binder驱动处理,会调用到IMessenger.Stub的onTransact()方法,最终会调用服务端的MessengerImpl的send()方法,继而通过Handler来sendMessage(),最后服务端的Handler来handleMessage();
四.与 AIDL 比较:
执行 IPC 时,使用 Messenger 要比使用 AIDL 实现更加简单,因为 Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。
对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果服务必须执行多线程处理,则应使用 AIDL 来定义接口。