AIDL–初探篇
前言
如果说你问我什么是AIDL,那我只知道它叫做Android Interface Definition Language,即安卓接口定义语言,还有只知道它是基于Binder机制从而实现进程间通信的,在普遍的开发下挺少用到的,而且用起来有些麻烦,以上就是我所知道的AIDL,而下面要写的内容是我看着书去了解的,但还是对于AIDL只用皮毛的知识了解,那不多说了,继续写下面的笔记,开始。
设计目的
设计AIDL这门语言的目的就是为了实现进程间通信。在Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL就是为了满足这种需求而诞生的。通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求
通常,暴露方法给其他应用进行调用的应用称为服务端,调用其他应用的方法的应用称为客户端,客户端通过绑定服务端的Service来进行交互
AIDL传递的数据类型
1.基本数据类型(除short类型)
2.String、charSequence
3.List :List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象,
map:Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
4.parcelable
AIDL的创建可以参考这篇文章https://www.jianshu.com/p/29999c1a93cd,看到这篇文章后,再想想自己想说的简直乱的一塌糊涂,为了不误导其他人,还是看这边文章比较稳。
我的笔记的内容
自动生成的AIDL包在以下目录
若新建后出现该异常
Process ‘command ‘E:\Android\SDK\build-tools\28.0.3\aidl.exe’’ finished with non-zero exit value 1
需要在aidl包下创建与Book类名相同的aidl文件,内容如下
这个一定要注意。
AIDL内容分析
DESCRIPTOR
表示Binder的唯一标识,一般为Binder的类名
asInterface(android.os.IBinder obj)
将Binder对象转换为com.hwt.myapplication.aidltest.IBookManage接口
将服务端的Binder对象转化为客户端所需的AIDL接口类型对象,这种是区分进程的,如果客户端和服务端位于同一个进程,则此方法返回的就是服务端本身的Sub对象,若不在同一进程,返回的是系统封装后的Sub.proxy对象。
public static com.hwt.myapplication.aidltest.IBookManage asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.hwt.myapplication.aidltest.IBookManage))) {
return ((com.hwt.myapplication.aidltest.IBookManage) iin);
}
return new com.hwt.myapplication.aidltest.IBookManage.Stub.Proxy(obj);
}
asBinder
用于返回当前Binder对象
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
onTransact
@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_basicTypes: {
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0 != data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(descriptor);
com.hwt.myapplication.aidltest.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.hwt.myapplication.aidltest.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(descriptor);
java.util.List<com.hwt.myapplication.aidltest.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
这个方法运行在服务端的Binder线程池中,当客户端跨进程请求时,远程请求会通过系统底层封装后交给这个方法处理,该方法原型为public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags),服务端通过code判断客户端要请求什么方法,然后从data中取出目标方法所需的参数(如果有目标方法的参数的话),然后就执行目标方法,执行完毕后,就向reply写入返回值(如果目标方法有返回值的话),这就是onTransact的执行过程。
注意:如果该方法返回false,那么说明客户端请求失败,因此可以通过这个方法做权限验证,验证哪个进程可以远程调用我们的服务
Proxy的方法
例如有参数的方法:
getBookList内部执行过程如下:
创建该方法所需的输入型Parcel对象_data,输出型Parcel对象_reply和返回值对象List,然后把该方法的参数信息写入到_data中(如果有参);接着调用transact进行RPC(远程过程调用)请求,同时挂起当前线程,然后服务端的onTransact方法被调用,直到RPC过程返回后,当前线程继续执行,并从_reply中取出RPC过程的返回结果,最后返回_reply中的数据。
@Override
public java.util.List<com.hwt.myapplication.aidltest.Book> getBookList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.hwt.myapplication.aidltest.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.hwt.myapplication.aidltest.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
没参数和没返回值的方法:
它和有参数方法的过程时一样的,只是没有返回值,所以不需要从_reply中取出返回值
整个AIDL的流程