csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论
Messenger是什么?
Messenger是基于AIDL实现的轻量级IPC方案。
这里立马就会有疑问为什么要它呢?明明有了aidl
上节课大家学完了aidl进行binder通信是否感觉到使用起来其实还是有点复杂,毕竟通信什么的要写aidl,而且客户端和服务端都需要aidl文件,两个过程里面都需要,相对来说还是比较麻烦,对于项目过程中可能就是一些简单的跨进程数据传递,就是调用几个非常非常简单的方法,很多觉得都要写aidl成本比较大,那么有没有更加简单的方案来解决这个问题呢?
那就是本节课要讲解的Messenger。
那么接下来直接讲他的使用过程:
1、服务端对Messenger的使用
服务端需要实现一个Handler用于处理客户端发来的跨进程通信信息:
Handler messengerHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case 1:
Log.i("test","MessengerService Messenger handleMessage msg = " + msg + " bundle key value = " + msg.getData().getString("bundleKey"));
Messenger clientSend = msg.replyTo;
Message toClientMsg = Message.obtain();
toClientMsg.what = 2;
// toClientMsg.obj = "I am replay from Server";
try {
clientSend.send(toClientMsg);
}catch (Exception e) {
Log.i("test","MessengerService clientSend error ",e);
}
break;
}
super.handleMessage(msg);
}
};
其次服务端构造出对应的Messenger:
服务端构造:
Messenger messenger = new Messenger(messengerHandler);
注意这里参数是messengerHandler即一个Handler
最后,当服务端的onBinder回调时候要返回Messenger的IBinder对象给客户端
@Nullable
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
2、客户端的使用
客户端还是和以前一样通过bindService在ServiceConnection类的onServiceConnected获取到服务端的返回的IBinder,从而获取到服务端的Messenger代理类,调用send函数发送Message。所以Messenger能发送的信息只有Message能携带的信息。
Intent intent = new Intent(MainActivity.this,MessengerService.class);
Log.i("test","MessengerService onClick ");
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
Log.i("test","MessengerService onServiceDisconnected name = " +name);
messengerServer = new Messenger(service);
sendMessageToServer();
} catch (Exception e) {
e.printStackTrace();
Log.i("test","error " ,e);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("test","client onServiceDisconnected name = " +name);
}
}, BIND_AUTO_CREATE);
void sendMessageToServer() throws RemoteException {
Message toServer = Message.obtain();
toServer.replyTo = messengerClientSend;
toServer.what = 1;
//toServer.obj = "hello I send from client"; 注意不可以 传递非parcel的对象,这个只能给obj赋值为parcel类型对象否则报错
Bundle bundle = new Bundle();
bundle.putString("bundleKey","bundleValue Client");
toServer.setData(bundle);
messengerServer.send(toServer);
}
大家这里注意客户端获取了服务端IBinder对象后,用它来构造客户端的Messenger,
messengerServer = new Messenger(service);
这里注意是和服务端不一样地方
有了服务端Messenger后,那么就可以通过它与服务端进行通信了,通信的内容载体是我们最为属性Message,对他就是和Handler搭配的Message,它就是具体消息体,即你需要发送什么消息,都是把内容转换成Message对象既可以,这里我们案例中传递一个Bundle的对象,这个Bundle对象可以利用键值对方式装载各种各样类型数据。和Intent传递数据Bundle是一样的。注意这里message对象还有一个属性是replyTo ,这个是Messenger类型的,字面意思就是说这个消息发送过去,如果对方需要回复,就可以通过消息中的replyTo 的Messenger对象来进行回复,这里是不是也和我们上节课讲的binder双向通信一样,所以说Messenger这种方式本身就相当于自带了双向通信
3 Messenger本质原理
Messenger其实本质上也是使用aidl进行实现了,只是这个aidl是在Framework层面进行写好了,不需要你写,你也就没有在意,没有看到。这里对他的源码进行分析一下:
public final class Messenger implements Parcelable {
private final IMessenger mTarget;
/**
* 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();//这个是handler对象获取IMessenger接口
}
/**
* Send a Message to this Messenger's Handler.
*
* @param message The Message to send. Usually retrieved through
* {@link Message#obtain() Message.obtain()}.
*
* @throws RemoteException Throws DeadObjectException if the target
* Handler no longer exists.
*/
public void send(Message message) throws RemoteException {
mTarget.send(message);//这其实调用是IMessenger接口的send
}
。。。。。省略
}
代码中注释提到的handler对象获取IMessenger接口,IMessenger 接口到底又是什么呢?
目前我没没有看到有aidl啊。。。
Handler的getIMessenger
@UnsupportedAppUsage
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);
}
}
大家看这里其实就是MessengerImpl ,是继承IMessenger.Stub,大家看到IMessenger.Stub是不是和aidl里面的接口和很熟悉啊。对它其实就是IMessenger.aidl文件生成的
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}
这里是不是看到期待已久的aidl了。。还是个oneway类型的哦