AIDL(1):简介
Android 接口定义语言 (AIDL)
1.AIDL是什么
AIDL(Android 接口定义语言)与您可能使用过的其他 IDL 类似。 您可以利用它定义客户端与服务使用进程间通信 (IPC) 进行相互通信时都认可的编程接口。
2.AIDL 用途
与Binder,Messenger一样,实现绑定服务。
3.何时才有必要用AIDL
- 只有允许不同应用的客户端用 IPC 方式访问服务,并且想要在服务中处理多线程时,才有必要使用 AIDL。
- 如果您不需要执行跨越不同应用的并发 IPC,就应该通过实现一个 Binder 创建接口;
- 如果您想执行 IPC,但根本不需要处理多线程,则使用 Messenger 类来实现接口。
4.AIDL 接口的调用是直接函数调用
5.AIDL 接口的实现必须是完全线程安全实现
6.oneway
oneway
关键字用于修改远程调用的行为。使用该关键字时,远程调用不会阻塞;它只是发送事务数据并立即返回。接口的实现最终接收此调用时,是以正常远程调用形式将其作为来自 Binder
线程池的常规调用进行接收。 如果 oneway
用于本地调用,则不会有任何影响,调用仍是同步调用。
7.aidl 文件内的数据类型
参数和返回值可以是任意类型,甚至可以是其他 AIDL 生成的接口。
默认情况下,AIDL 支持下列数据类型:
- 基本类型(如
int
、long
、char
、boolean
等等 String
- CharSequence
- List ,另一端实际接收的具体类始终是
ArrayList
,但生成的方法使用的是List
接口。注意,是始终 - Map,另一端实际接收的具体类始终是
HashMap
,但生成的方法使用的是Map
接口。注意,是始终
List和Map中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。
8.在aidl中定义服务接口的注意事项
- 方法可带零个或多个参数,返回值或空值。
- 所有非基本类型参数都需要指示数据走向的方向标记。可以是
in
、out
或inout
(见以下示例) - 原语默认为
in
,不能是其他方向。 - 所有代码注释都包含在生成的
IBinder
接口中(import 和 package 语句之前的注释除外) - 只支持方法;您不能公开 AIDL 中的静态字段。注意,是不能公开,没说不能定义。
9.实现 AIDL 接口时应注意遵守以下这几个规则
- 由于不能保证在主线程上执行传入调用,因此您一开始就需要做好多线程处理准备,并将您的服务正确地编译为线程安全服务。
- 默认情况下,RPC 调用是同步调用。如果您明知服务完成请求的时间不止几毫秒,就不应该从 Activity 的主线程调用服务,因为这样做可能会使应用挂起(Android 可能会显示“Application is Not Responding”对话框)— 您通常应该从客户端内的单独线程调用服务。
- 您引发的任何异常都不会回传给调用方。
10.在aidl接口中的非基本类型是如何在进程间传递的?
这是本文最重要一条
通过 IPC 接口把某个类从一个进程发送到另一个进程是可以实现的。
前提是必须确保该类的代码对 IPC 通道的两端都可用,并且该类必须支持Parcelable
接口。支持 Parcelable
接口很重要,因为 Android 系统可通过它将对象分解成可编组到各进程的原语。
11.如何创建支持 Parcelable
协议的类
必须执行以下操作:
- 让您的类实现
Parcelable
接口。 - 实现
writeToParcel
,它会获取对象的当前状态并将其写入Parcel
。 - 为您的类添加一个名为
CREATOR
的静态字段,这个字段是一个实现Parcelable.Creator
接口的对象。 - 最后,创建一个声明可打包类的
.aidl
文件(按照下文Rect.aidl
文件所示步骤)。如下:1 package android.graphics; 2 3 // Declare Rect so AIDL can find it and knows that it implements 4 // the parcelable protocol. 5 parcelable Rect;
示例
1 import android.os.Parcel; 2 import android.os.Parcelable; 3 4 public final class Rect implements Parcelable { 5 public int left; 6 public int top; 7 public int right; 8 public int bottom; 9 10 public static final Parcelable.Creator<Rect> CREATOR = new 11 Parcelable.Creator<Rect>() { 12 public Rect createFromParcel(Parcel in) { 13 return new Rect(in); 14 } 15 16 public Rect[] newArray(int size) { 17 return new Rect[size]; 18 } 19 }; 20 21 public Rect() { 22 } 23 24 private Rect(Parcel in) { 25 readFromParcel(in); 26 } 27 28 public void writeToParcel(Parcel out) { 29 out.writeInt(left); 30 out.writeInt(top); 31 out.writeInt(right); 32 out.writeInt(bottom); 33 } 34 35 public void readFromParcel(Parcel in) { 36 left = in.readInt(); 37 top = in.readInt(); 38 right = in.readInt(); 39 bottom = in.readInt(); 40 } 41 }
如果您使用的是自定义编译进程,切勿在您的编译中添加 .aidl
文件。 此 .aidl
文件与 C 语言中的头文件类似,并未编译。
AIDL 在它生成的代码中使用这些方法和字段将您的对象序列化和反序列化。
12.有关调用 IPC 服务的几点说明
- 对象是跨进程计数的引用。
- 您可以将匿名对象作为方法参数发送。