之前有一篇是讲到AIDL的使用,其实在系统那里已经为aidl生产了一个Binder类,那么我们现在就来逐一分析一下:
首先,在这个IMyAIDL接口中继承了android.os.IInterface这个接口,所有可以在Binder中传输的接口都要继承IInterface这个接口。
public interface IMyAIDL extends android.os.IInterface {}
在这个接口里面,声明了我们在aidl里面定义的方法
public java.util.List<com.example.xing.aidldemo.Person> add(com.example.xing.aidldemo.Person person) throws android.os.RemoteException;
还有就是定义了一个Stub的静态内部类,这个内部类也继承了Binder,还实现了本身的接口IMyAIDL,所以这个Stub相当于就是一个Binder。在服务器端new一个Binder的时候,new IMyAIDL.Stub(),获得的就是这个Stub。
public static abstract class Stub extends android.os.Binder implements com.example.xing.aidldemo.IMyAIDL {}
在里面定义了两个静态变量
private static final java.lang.String DESCRIPTOR = "com.example.xing.aidldemo.IMyAIDL";
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
名称 | 说明 |
---|---|
DESCRIPTOR | 通常就是Binder的包名 |
TRANSACTION_add | 是我们在接口里面定义的add()方法的ID标志 |
在这个Stub类接着看下去,发现这样一个方法:
public static com.example.xing.aidldemo.IMyAIDL asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.xing.aidldemo.IMyAIDL))) {
return ((com.example.xing.aidldemo.IMyAIDL)iin);
}
return new com.example.xing.aidldemo.IMyAIDL.Stub.Proxy(obj);
}
是不是感觉似曾相识,没错就是在客户端的时候拿到远程服务的时候调用了这个方法。
iMyAidl = IMyAIDL.Stub.asInterface(iBinder);
这个方法就是为了将服务器端的Binder对象转化为客户端的可以使用的aidl对象。通常这里需要进行判断,如果客户端和服务器端是处于同一个进程里面,返回的就是服务器的Binder,如果不是同一个进程的话,就返回new com.example.xing.aidldemo.IMyAIDL.Stub.Proxy(obj)。这里出现了Proxy,这个究竟是什么呢?不过从字面上理解应该就是代理,那我们找找Proxy在哪里出现?
private static class Proxy implements com.example.xing.aidldemo.IMyAIDL {
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;
}
@Override
public java.util.List<com.example.xing.aidldemo.Person> add(com.example.xing.aidldemo.Person person) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.xing.aidldemo.Person> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((person != null)) {
_data.writeInt(1);
person.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.xing.aidldemo.Person.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
原来这个类是Stub的静态内部类,也是实现了IMyAIDL这个接口,所以同样实现了add()这个方法。就是说我们在客户端拿到的并非真正的远程服务IBinder,而只是代理而已。
那么直接看到我们的add()方法中,这里定义两个parcel
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
_data用于写入参数(如果有的话),_reply用于数据的返回。
接着往下看
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((person != null)) {
_data.writeInt(1);
person.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.xing.aidldemo.Person.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
这时候看到调用的mRemote.transact(),这个mRemote是Stub的实例,相当于就是调用IBinder底层的onTransact()方法,将从onTransact()返回的数据返回。
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_add: {
data.enforceInterface(DESCRIPTOR);
com.example.xing.aidldemo.Person _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.xing.aidldemo.Person.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
java.util.List<com.example.xing.aidldemo.Person> _result = this.add(_arg0);
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
onTransact里面有4个参数:
参数 | 说明 |
---|---|
code | 用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法 |
data | 客户端传递过来的参数 |
replay | 服务器返回回去的值 |
flags | 标明是否有返回值,0为有(双向),1为没有(单向) |
当通过code判断执行哪个方法的时候,首先会从data中获取传进来的参数,接着执行目标方法,具体的实现就是在我们服务端编写的,this.add(_arg0),执行完毕之后,就将返回的数据写进reply中
reply.writeNoException();
reply.writeTypedList(_result);
基本上执行的过程就是这样了。
其实Android 下的Binder机制主要就是有3部分:服务端接口,Binder驱动和客户端接口。
服务端的接口:实际上就是一个Binder实例,当它被创建的时候,会自动创建一个线程,接收Binder驱动传来的消息执行onTransact()方法,根据参数的不同,执行不同的方法,在AIDL中相当于Stub。
Binder驱动:也是一个Binder的实例,客户端通过这个远程访问服务端。就是客户端和服务器端之间的桥梁。
客户端接口:获得Binder实例,调用Transact()。在AIDL中,相当于就是Proxy。
注意:
- 当客户端发起远程调用的时候,当前线程会被挂起,直到数据返回,所以远程方法如果是一个很耗时的,就不要在主线程发起请求
- 服务端的Binder方法是在一个线程池里面运行的