上篇文章大致讲了AIDL,本篇的主人公是messenger,其底层原理也是AIDL,利用Android的binder机制实现的,下面简单记录一下使用方法
一.messenger 简介
Messenger “信使”,顾名思义,它的作用就是传递信息。
Messenger 有两个构造函数:
- 以 Handler 为参数
- 以 Binder 为参数
下面为两种构造方法的代码
private final IMessenger mTarget;
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target); //和 AIDL 很相似
}
看下 Handler.getIMessenger() 源码:
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
这个 IMessanger
应该也是个 AIDL 生成的类吧,看下源码,果然是:
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";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static android.os.IMessenger asInterface(...}
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 {...}
private static class Proxy implements android.os.IMessenger {...}
public void send(android.os.Message msg)
throws android.os.RemoteException;
}
Handler
中 MessengerImpl
实现了这个方法,就是使用 Handler 将消息发出去:
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
Messenger 中持有一个 IMessenger 的引用,在构造函数中可以通过 Handler 或者 Binder 的形式获得最终的 IMessenger 实现,然后调用它的 send() 方法。
Messenger 其实就是 AIDL 的简化版,它把接口都封装好,我们只需在一个进程创建一个 Handler 传递给 Messenger,Messenger 帮我们把消息跨进程传递到另一个进程,我们在另一个进程的 Handler 在处理消息就可以了。
二.服务端
服务端只需要创建一个 Messenger 对象,然后给它传递一个 Handler,在 Handler 中处理消息,其中要注意的是谁调用send就是给谁发消息,例如msg.replyTo.send(replyMsg)这里msg.replyTo是客户端的messenger,所以是给客户端发消息,也可以说是给客户端回信,贴代码:
public class MessengerService extends BaseService {
private final String TAG = this.getClass().getSimpleName();
Messenger mMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(final Message msg) {
if (msg != null && msg.arg1 == ConfigHelper.MSG_ID_CLIENT) {
if (msg.getData() == null) {
return;
}
String content = (String) msg.getData().get(ConfigHelper.MSG_CONTENT);
LogUtils.d(TAG, "Message from client: " + content);
//回复消息给客户端
Message replyMsg = Message.obtain();
replyMsg.arg1 = ConfigHelper.MSG_ID_SERVER;
Bundle bundle = new Bundle();
bundle.putString(ConfigHelper.MSG_CONTENT, "听到你的消息了,请说点正经的");
replyMsg.setData(bundle);
try {
msg.replyTo.send(replyMsg);//这里是给客户端发消息,msg.replyTo得到的是客户端的messenger
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
@Nullable
@Override
public IBinder onBind(final Intent intent) {
return mMessenger.getBinder();//这里是把服务端的binder通过service返回出去,让客户端可以得到
}
}
三.客户端
需要注意的是这里是通过ServiceConnection的onServiceConnected 返回的 IBinder 以得到服务端的messenger,从而通过服务端的messenger调用send方法向服务端发送消息,而此处的message.replyTo 就是告诉服务端接收回信的客户端的messenger,贴代码:
public class IPCTestActivity extends BaseActivity {
private final String TAG = this.getClass().getSimpleName();
@BindView(R.id.tv_result)
TextView mTvResult;
@BindView(R.id.btn_add_person)
Button mBtnAddPerson;
@BindView(R.id.et_msg_content)
EditText mEtMsgContent;
@BindView(R.id.btn_send_msg)
Button mBtnSendMsg;
/**
* 客户端的 Messenger
*/
Messenger mClientMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(final Message msg) {
if (msg != null && msg.arg1 == ConfigHelper.MSG_ID_SERVER){
if (msg.getData() == null){
return;
}
String content = (String) msg.getData().get(ConfigHelper.MSG_CONTENT);
LogUtils.d(TAG, "Message from server: " + content);
}
}
});
//通过 IBinder 得到的服务端的 Messenger
private Messenger mServerMessenger;
private ServiceConnection mMessengerConnection = new ServiceConnection() {
@Override
public void onServiceConnected(final ComponentName name, final IBinder service) {
mServerMessenger = new Messenger(service);
}
@Override
public void onServiceDisconnected(final ComponentName name) {
mServerMessenger = null;
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
ButterKnife.bind(this);
bindAIDLService();
bindMessengerService();
}
private void bindMessengerService() {
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mMessengerConnection, BIND_AUTO_CREATE);
}
@OnClick(R.id.btn_send_msg)
public void sendMsg() {
String msgContent = mEtMsgContent.getText().toString();
msgContent = TextUtils.isEmpty(msgContent) ? "默认消息" : msgContent;
Message message = Message.obtain();
message.arg1 = ConfigHelper.MSG_ID_CLIENT;
Bundle bundle = new Bundle();
bundle.putString(ConfigHelper.MSG_CONTENT, msgContent);
message.setData(bundle);
message.replyTo = mClientMessenger; //指定回信人是客户端定义的
try {
mServerMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mMessengerConnection);
}
}
最后再通过调用 bindService 将 serviceConnection 传入,绑定服务端service即可,此处如果服务端和客户端没有在同一个工程,那么intent 需要使用隐式跳转指定服务端的service,例如:
Intent service = new Intent();
service.setClassName("com.example.aidlservertest""com.example.aidlservertest.AIDLService";//此处填服务端的包名和服务端的包名+service名字
bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);