AIDL的全称是Android Interface definition language,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口,用处当然就是用来进程间的通信和方法调用了。其实AIDL是Binder的一个上层实现,它简化了Binder的使用,在编译时,由编译器帮助我们完成了大量工作(例如,生成AIDL文件所对应的.java类)。
先介绍一下AIDL进程间通信的流程。
AIDL通信流程简介 1. AIDL接口的创建AIDL文件中,并不是所有的数据类型都是可以使用的,它支持的数据类型有:
基本数据类型(int,long,char,boolean,double等) String和CharSequence List:只支持ArrayList,而且list中的元素也必须是 AIDL 支持的类型 Map:只支持HashMap,里面的key和value也必须是AIDL支持的类型 Parceable:所有实现了 Parceable 接口的对象 AIDL:所有的 AIDL 接口本身也可以在 AIDL 文件中使用,所以 IBinder 类型也是支持的 2. 服务端服务端首先要创建一个 Service 用来监听客户端的请求,然后将在对应AIDL文件中声明的接口实现,并且通过onbind函数返回相应 IBinder 对象即可。
3. 客户端客户端所要做的事情就稍微简单一些,首先需要绑定服务端的Service,绑定成功后,将服务端返回的 IBinder 对象转成AIDL接口所属的类型,接着就可以调用AIDL中的方法了。
AIDL文件及参数说明 自定义类型通常,AIDL默认支持基础类型参数及返回值的数据传递。如果AIDL文件中用到了自定义的Parcelable对象,那么必须新建一个和它同名的AIDL文件,并在其中声明它为Parcelable类型。
例如,我们定义了一个名为RequestData的数据类型,要想在AIDL中使用它,除了它自己的RequestData.java文件之外,我们还必须定义一个名为RequestData.aidl的文件(包名必须和RequestData.java中的相同),内容如下:
package com.testaidl;
parcelable RequestData;
参数标志
AIDL中除了基本数据类型,其他类型的参数必须标上方向:in,out或者inout, in表示输入型参数,out表示输出型参数,inout表示输入输出型参数。
我们要根据实际需要去指定参数类型,不能一概使用out或者inout,因为这在底层实现是有开销的。
接口及同步AIDL接口中只支持方法,不支持声明静态常量,这一点区别于传统的接口。
客户端调用服务端方法,被调用的方法运行在服务端的Binder线程池中,同时客户端线程会被挂起,这个时候如果服务端方法执行比较耗时,就会导致客户端线程长时间阻塞,而如果这个客户端线程是UI线程的话,就会导致客户端ANR,所以如果知道服务端的一个方法是耗时的,就要避免在客户端的UI线程中去调用该远程方法。
但是有一种方法可以发起非阻塞式的远程调用:就是在声明AIDL时,加上oneway关键字。
相比平常自定义的 aidl,多了 oneway 的关键字,声明和不声明 oneway 关键字的在于生成 Java 类中一个参数:
不声明 oneway 时,mRemote.transact 传入的最后一个参数是 0;声明 oneway 时,mRemote.transact 传入的最后一个参数是 android.os.IBinder.FLAG_ONEWAY 。
FLAG_ONEWAY 的作用就是让客户端能够非阻塞的调用远程方法。
系统Service的调用示例我们以系统服务的调用来分析AIDL的使用过程。
系统服务的调用过程首先通过 ServiceManager.getService()方法获取一个IBinder对象,但是这个IBinder对象不能直接调用,必须要通过asInterface方法转成对应的IInterface对象才可以使用,如果在同一个进程中(当然,这是跨进程通信,这种情况很少),就会直接返回通过attachInterface方法设置的IInterface对象(上面代码所述),但是如果不是在同一个进程中,就会先通过IBinder对象创建一个Proxy对象(服务的本地代理对象),然后在Proxy对象中通过调用IBinder对象的transact方法调用到服务进程的Service中,实现了跨进程的通信。
以AMS为例,我们来看具体实现。
AMS的服务调用关键实现AIDL 文件生成的类中会自动生成两个类,Proxy 类和 Stub 类,对应的是 ActivityManagerProxy 和 ActivityManagerService 类。
我们使用ActivityManager实现AMS通信时,在其内部都是调用ActivityManagerNative来实现的。我们来看相关类的继承关系:
原创文章 13获赞 0访问量 3969
关注
私信
展开阅读全文
作者:卜大爷