1.aidl支持类型
* Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。
* String 类型。
* CharSequence类型。
* List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。List可以使用泛型。
* Map类型:Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelab le。Map是不支持泛型的。
2.定义方式
定义IBookManager.aidl,在adil文件中声明相应的方法
package com.example.arvin.myapplication;
// Declare any non-default types here with import statements
import com.example.arvin.myapplication.Book;
interface IBookManager {
List getBookList();
void addBook(in Book book);
Book findBook(in String bookId);
void addBookOut(out Book book);
}
aidl支持自定义类型,但是必须序列化(实现parcelable)
自定义parceable需要声明一个同名的aidl文件 用parcelable 声明类型
// Books.aidl
package com.example.arvin.myapplication;
// Declare any non-default types here with import statements
parcelable Book;
aidl使用默认支持的类型不需要导包,使用其他类型需要导包,即使是在同一个包路径下,这点和java是有区别的
3.aidl自动生成文件源码
先截个图
可以看到,aidl自动生成了同名java文件 是一个接口类型,和aidl中一样
java文件的内容包括两部分
//第一部分
public void addBook(com.example.arvin.myapplication.Book book) throws android.os.RemoteException;
public com.example.arvin.myapplication.Book findBook(java.lang.String bookId) throws android.os.RemoteException;
public void addBookOut(com.example.arvin.myapplication.Book book) throws android.os.RemoteException;
这三个方法是aidl接口中声明的方法
第二部分就Stub,继承Binder,而Binder 实现了IBinder。Stub还实现了jiekaidl声明的接口(本例中是IBookManager)
展开Stub 看看具体的东西
看起来也比较清楚,
1.声明了4个整型常量,对应aidl中声明的方法
2.DESCRIPTOR aidl描述,通常使用类全名
3.定义了一个内部类Proxy,从名字上推测上代理类,干嘛用的后面看
4.实现了Binder里面一些方法,比如onTransact,再比如asBinder, 先不管,后面看呗
看起来也还挺清楚
1.声明了一个IBinder对象,在构造方法中赋值,中asBinder()方法中返回这个对象
2.实现了我们在Aidl接口中声明的4个方法。
一起来看看这几个方法
这里先对比前两个方法getBookList()和addBook(int Book book)
首先定义了两个Parcel 对象,通过对比我们可以看出来,_data应该是用来保存传入参数的,_reply是返回值
if ((book != null)) { //传入参数不为空,writeInt(1) 并写入_data中
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException(); //这一句 如果没满足特定条件直接抛出异常,估计应该是校验用的
_result = com.example.arvin.myapplication.Book.CREATOR.createFromParcel(_reply); //返回对象赋值
看这里,看这里
当 形参声明为 out的时候,_data是没有被赋值的,先标个记,一会来看
if ((0 != _reply.readInt())) {
book.readFromParcel(_reply);
}
//这一句应该是改变了传入参数,就是说client的数据会受到影响,发生变化咯
可以看到这里面的操作基本都是赋值,那实际工作的代码应该就是
mRemote.transact(Stub.TRANSACTION_addBookInOut, _data, _reply, 0);
跟踪代码发现,这里最终会去走
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
上面的声明很清楚了,code就是最上面提到的生成的对应4个方法的int值,data就是传参,reply就是保存返回值的
来看一下具体的代码 不截图来上源码好了
@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_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.arvin.myapplication.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.example.arvin.myapplication.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.arvin.myapplication.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_findBook: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
com.example.arvin.myapplication.Book _result = this.findBook(_arg0);
reply.writeNoException();
if ((_result != null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_addBookOut: {
data.enforceInterface(DESCRIPTOR);
com.example.arvin.myapplication.Book _arg0;
_arg0 = new com.example.arvin.myapplication.Book();
this.addBookOut(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_addBookInOut: {
data.enforceInterface(DESCRIPTOR);
com.example.arvin.myapplication.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.arvin.myapplication.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBookInOut(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
通过代码很容易看出来,Proxy是运行在服务端的,为什么这么说呢
这里面有这一句
java.util.List
class Bookmanager extends IBookManager.Stub {
...
}
至此,aidl的调用流程也就很清楚了,然后有请灵魂画师给画个图
什么鬼这是???
还是请出任玉刚老师的图吧(这个不算侵权吧)
看起来还是蛮像的啊
public void readFromParcel(Parcel reply) {
bookId = reply.readString();
bookName = reply.readString();
}
那就先到这里了,有时间的话再去深入Binder,IBinder,记得开头好像有几个asBinder的坑没填,后面填上