AIDL 基础语法:接口定义、package 声明、import 语句、方法声明

AIDL (Android Interface Definition Language) 是 Android 进程间通信(IPC)的核心契约语言。它使用与 Java 相近的语法定义跨进程接口,编译后生成 Binder 桩代码。本章从最基础的语法单元出发,掌握接口文件的结构、命名空间、依赖引用和方法签名。

1.1 AIDL 文件整体结构

一个标准的 AIDL 接口文件由三部分组成:package 声明(必须)、import 语句(可选)、接口定义与方法声明(必须)。文件扩展名为 .aidl,存放在 src/main/aidl/ 目录下,包路径需与 Java 源码包路径对应。

组成部分是否必须作用
package 声明是定义接口所属的命名空间,必须与文件所在目录一致
import 语句否引入自定义的 parcelable 类型或其他 AIDL 接口
接口及方法声明是使用 interface 关键字定义 IPC 契约,内部包含若干抽象方法
关键原则:AIDL 只支持声明方法,不支持成员变量或静态常量。所有参数和返回值必须是 AIDL 支持的数据类型(基本类型、String、CharSequence、List、Map、Parcelable、其他 AIDL 接口)。

1.2 package 声明

写法与 Java package 相同,位于文件第一行(忽略注释)。例如:

package com.example.myapp.aidl;

文件必须存放在 src/main/aidl/com/example/myapp/aidl/ 目录下。包名定义后,编译生成的 Java 接口类也会自动放入该包中。

常见错误:package 声明的路径与磁盘目录不一致会导致编译报错 invalid package reference。检查 .aidl 文件的实际目录是否完全匹配 package 声明。

1.3 import 语句

当方法参数或返回值涉及自定义的 Parcelable 类型,或者引用其他 AIDL 接口时,必须使用 import 引入。

import com.example.myapp.model.User;
import com.example.myapp.aidl.ICallback;

如果 Parcelable 类与当前 AIDL 文件在同一包下,import 可省略。系统内置类型(如 String、List、Map)无需 import。

  • Parcelable 类:需要同时提供同名 .java 文件(实现 Parcelable 接口)和对应 .aidl 占位声明文件(内容仅为 package + parcelable 类名;)。
  • AIDL 接口引用:直接引用另一个 AIDL 接口,编译时会自动链接。

1.4 接口定义与方法声明

使用 interface 关键字定义接口,内部声明抽象方法。支持的重载、入参方向标记与基本数据类型如下:

语法元素说明
interface IMyService { … }接口定义,名称建议以 I 开头
int add(int a, int b);无方向标记(in 为默认)
void setUser(in User user);in 方向:数据从客户端流向服务端
void getUser(out User user);out 方向:数据从服务端返回客户端
void updateUser(inout User user);inout 方向:双向传递
List<String> getNames();泛型支持,需指定具体类型

以下是完整的 AIDL 接口示例:

// IBookManager.aidl
package com.example.library.aidl;

import com.example.library.model.Book;

interface IBookManager {
    List<Book> getBookList();
    void addBook(in Book book);
    void registerCallback(in IOnBookChangeListener listener);
    void unregisterCallback(in IOnBookChangeListener listener);
}
调试小技巧:在 AS 中创建 .aidl 文件后,编译一次,即可在 build/generated/source/aidl/debug/ 下看到生成的 Java 桩类(IBookManager.java)。阅读生成的 Stub 与 Proxy 内部类,能加深对 Binder 通信机制的理解。

1.5 AIDL 基础语法关系全景图

下图展示了 AIDL 接口文件从结构到编译产物的整体脉络:

AIDL 接口文件组成与编译流程 package 声明 必须,匹配目录 import 语句 可选,引入Parcelable/接口 接口与方法声明 核心契约 AIDL 编译器(aidl.exe / AS 构建) 解析语法 → 生成 Java 接口 + Stub + Proxy 生成的 Java 桩类 IMyService.java 内部类 Stub(服务端)、Proxy(客户端) 关键理解 package → 确定生成类的位置;import → 引用外部类型;方法签名 → 定义 transact code 方向标记 (in/out/inout) 影响序列化拷贝方式,直接影响 IPC 性能

1.6 性能与稳定性注意点

  • 方法数量控制:每个 AIDL 接口的方法不宜超过 15 个,过多方法会增加 Binder 事务编号管理的复杂度,且加大维护成本。
  • 方向标记影响性能:in 最快(仅序列化一次),out 和 inout 涉及反序列化和回写,会增加拷贝次数。非必要不使用 inout。
  • 避免大对象传递:1MB 以上数据通过 AIDL 传递会触发 Binder 缓冲区溢出,应改为文件描述符或共享内存。
  • 保持接口幂等:跨进程调用可能被重复执行,回调接口应做好去重或状态检查。
实战建议:每次新建 AIDL 接口后,先编译一次确认无语法错误,再编写 Service 端实现。推荐在 build.gradle 中配置 aidl.enableTrace true 可输出更详细的编译日志,便于定位 import 路径问题。