AIDL(Android Interface Definition Language)是Android系统中用于跨进程通信(IPC)的接口定义语言,它基于Binder机制,允许不同进程的客户端与服务端通过预定义的接口进行数据交互。
核心特点:
AIDL文件本质是定义接口及其方法参数/返回值的IDL语法,示例如下:
// IBookManager.aidl package com.example.bookmanager; // 定义接口 interface IBookManager { List<Book> getBooks(); // 方法声明(无实现) void addBook(Book book); } // 定义数据类型 parcelable Book; // 必须实现Parcelable接口
关键规则:
parcelable
或基础类型。编译时,系统会生成以下关键类:
| 文件名 | 作用 |
|———————–|——————————|
| IBookManager.java | 接口Stub类(实现IBinder接口)|
| IBookManager.Stub.java| 客户端代理类(实现接口) |
| IBookManager.aidl | 接口定义文件 |
典型调用流程:
IBookManager.Stub
实例并绑定Binder。ServiceConnection
获取服务端的Binder。IBookManager.Stub.asInterface(binder)
获取代理对象。定义AIDL文件
// 在src/main/aidl目录下创建IBookManager.aidl package com.example.bookmanager; interface IBookManager { Book getBook(int id); } parcelable Book; // 需实现Parcelable接口
实现Parcelable数据类
public class Book implements Parcelable { private int id; private String title; // 构造方法、getter/setter省略 @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeString(title); } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel in) { return new Book(in); } @Override public Book[] newArray(int size) { return new Book[size]; } }; private Book(Parcel in) { id = in.readInt(); title = in.readString(); } }
服务端实现
public class BookService extends Service { private final IBookManager.Stub mBinder = new IBookManager.Stub() { @Override public Book getBook(int id) { // 查询数据库逻辑... return new Book(id, "Demo Book"); } }; @Override public IBinder onBind(Intent intent) { return mBinder; } }
客户端调用
// 绑定服务 Intent intent = new Intent(this, BookService.class); bindService(intent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IBookManager bookManager = IBookManager.Stub.asInterface(service); try { Book book = bookManager.getBook(1); // 远程调用 Log.d("Client", "Book: " + book.getTitle()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) {} }, Context.BIND_AUTO_CREATE);
特性 | AIDL | Messenger | ContentProvider |
---|---|---|---|
数据类型支持 | 任意Parcelable类型 | Bundle | 标准数据类型 |
调用方向 | 双向(客户端→服务端) | 单向(客户端→服务端) | 单向(客户端→服务端) |
性能 | 高(直接Binder调用) | 中(消息队列处理) | 低(URI解析+数据封装) |
适用场景 | 高频复杂交互 | 简单任务异步处理 | 数据共享 |
实现复杂度 | 高(需定义接口/实现) | 低(基于Handler) | 中(需管理URI权限) |
问题1:编译报错No such package
原因:AIDL文件包名与Java目录结构不一致。
解决:确保package
声明与Java代码包名完全匹配,如package com.example.myapp;
。
问题2:运行时BadParcelableException
原因:客户端和服务端使用不同版本的AIDL文件。
解决:重新编译所有模块,保证AIDL文件同步更新。
问题3:大数据量传输导致ANR
优化方案:
BiMap
代替频繁RPC调用。ParcelFileDescriptor
共享文件描述符。Q1:AIDL是否支持回调接口?如何实现服务端主动通知客户端?
A1:
AIDL本身不支持回调,但可通过以下方式实现反向通信:
void registerCallback(ICallback callback); void unregisterCallback(ICallback callback);
public void sendEventToClients(Event event) { for (ICallback callback : mCallbacks) { try { callback.onEvent(event); } catch (RemoteException e) { mCallbacks.remove(callback); } } }
ICallback
接口并注册。Q2:能否混合使用AIDL和其他IPC方式?例如同时使用Messenger和AIDL?
A2:
可以混合使用,但需注意: