比如有这样一个需求,APP检测到需要更新,为了不影响我们本应用,我们需要别外开启一个服务进程来下载这个APK,这就涉及到了二个进程进行通信.
这样我们就可以使用Messenger,Messenger他其实就是对AIDL的再次封装.
Messenger里面有二个构造方法,分别是传Handler,IBinder. 还有一个成员变量IMessenger target, 不管哪种构造方法都是为了给target赋值,
当以Handler(handler)作为构造参数的时候,会调用handler.getIMessenger方法获取到一个IMessenger并赋值给target.而Handler的getIMessenger方法里就会实例化出一个MessengerImpl也就是IMessenger这个接口的实现类.
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
//Handler里的方法
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
//Handler中的私有的静态内部类
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
当以IBinder(binder)作为参数的时候,他会通过IMessenger.Stub.asInstace(binder)实例化出IMessenger.Stub.Proxy代理类
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
先来说服务端(DownLoadService) 在DownLoadService中的生命周期onBInd方法中需要返回一个IBinder.这个时候我们就需要创建出一个以Handler为构造参数的Messenger,并通过Messenger.getBinder()返回.
public class MessengerSevice extends Service {
Messenger mMessenger = new Messenger(new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
String sfsdf = msg.getData().getString("sfsdf");
Messenger replyTo = msg.replyTo;
return false;
}
}));
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
Messenger.getBinder()返回的其实就是MessengerImpl,为什么呢,
public IBinder getBinder() {
//1.mTarget
return mTarget.asBinder();
}
在注释1中,这个mTarget其实就是在构造方法中的MessengerImpl,而mTarget.asBinder在aidl生成的接口文件中得到的就是自己.
所以在客户端bindService绑定成功的时候,获取到的IBinder就是服务端的MessengerImpl
在绑定成功回调方法中,通过以服务端的IBinder为参数构造出可以跟服务端发送消息的Messenger
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//1:service
mServiceMessenger = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mServiceMessenger = null;
}
};
在注释1中的service其实就是服务端的MessengerImpl.
当客户端要向服务端发送消息的时候,mServiceMessenger.send(msg);
public void sendMessage(View view) {
if (mServiceMessenger != null) {
try {
Message obtain = Message.obtain();
//这里先不做讨论,下面会讲
obtain.replyTo = mClientMessenger;
//1:send方法
mServiceMessenger.send(obtain);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
在注释1中的send方法是怎么操作的: Messenger.send方法其实是通过IMessenger.send方法来操作的,而这个时候的IMessenger就是服务端的IBinder的实现类MessengerIml,就是通过这个类的send方法来发送消息的
再来看这个类
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
很明显了,就是通过自身的Handler来sendMessage的,这样就会来到服务端的handlerMessage方法中,就可以获取到里面的参数.
这就客户端向服务端发送数据服务端就可以接收.这个时候下载的操作就可以在服务端操作了.
下载进度是如何传递给客户端的呢
这个就相对简单,在Message这个类中有一个成员变量 replyTo.我们在客户端的时候就需要以Handler为参数构造出一个Messenger.并赋值给replyTo
public void sendMessage(View view) {
if (mServiceMessenger != null) {
try {
Message obtain = Message.obtain();
//这里就将客户端的Messenger传递给了服务端
obtain.replyTo = mClientMessenger;
mServiceMessenger.send(obtain);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
所以服务端拿到了客户端的Messenger就可以使用客户端的Messenger来向客户端传递消息.
public boolean handleMessage(Message msg) {
String sfsdf = msg.getData().getString("sfsdf");
Messenger replyTo = msg.replyTo;
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString("client","我是服务端,向客户端发送消息");
message.setData(bundle);
try {
replyTo.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
return false;
}
这样双方就可以互相交流
最后赋上AIDL文件生成的java类
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: /Volumes/windows/android_studio/binder/app/src/main/aidl/con/ancely/binder/IMessenger.aidl
*/
package con.ancely.binder;
// Declare any non-default types here with import statements
public interface IMessenger extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements con.ancely.binder.IMessenger {
private static final java.lang.String DESCRIPTOR = "con.ancely.binder.IMessenger";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an con.ancely.binder.IMessenger interface,
* generating a proxy if needed.
*/
public static con.ancely.binder.IMessenger asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof con.ancely.binder.IMessenger))) {
return ((con.ancely.binder.IMessenger) iin);
}
return new con.ancely.binder.IMessenger.Stub.Proxy(obj);
}
@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 {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_send: {
data.enforceInterface(descriptor);
con.ancely.binder.Message _arg0;
if ((0 != data.readInt())) {
_arg0 = con.ancely.binder.Message.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.send(_arg0);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements con.ancely.binder.IMessenger {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override
public void send(con.ancely.binder.Message message) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((message != null)) {
_data.writeInt(1);
message.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_send, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_send = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void send(con.ancely.binder.Message message) throws android.os.RemoteException;
}