Android AIDL进程间通信详解
AIDL (Android Interface Definition Language) 是 Android 中用于进程间通信 (IPC) 的一种机制。它允许不同进程中的对象进行跨进程通信,通常用于服务与客户端之间的交互。
一、AIDL基本概念
- 作用:实现跨进程的方法调用
- 特点:
- 基于Binder机制实现
- 支持同步调用
- 支持基本数据类型和Parcelable对象
- 需要明确定义接口
二、AIDL使用步骤
1. 创建AIDL文件
在src/main/aidl
目录下创建.aidl
文件,例如IBookManager.aidl
:
// IBookManager.aidl
package com.example.aidl;
// 声明接口
interface IBookManager {
// 基本数据类型示例
int getBookCount();
// 传递自定义对象示例(需实现Parcelable)
Book getBook(in int bookId);
// 添加书籍
void addBook(in Book book);
// 获取所有书籍
List<Book> getBookList();
}
// 如果使用自定义类型,需要单独声明
parcelable Book;
2. 实现Parcelable对象
对于自定义对象,需要实现Parcelable
接口:
public class Book implements Parcelable {
public int id;
public String name;
// 实现Parcelable接口的方法
@Override
public int describeContents() { return 0; }
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel source) {
return new Book(source);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
protected Book(Parcel in) {
id = in.readInt();
name = in.readString();
}
}
3. 创建对应的AIDL文件
为自定义对象创建对应的AIDL文件Book.aidl
:
// Book.aidl
package com.example.aidl;
parcelable Book;
4. 实现Service
public class BookManagerService extends Service {
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
private Binder mBinder = new IBookManager.Stub() {
@Override
public int getBookCount() throws RemoteException {
return mBookList.size();
}
@Override
public Book getBook(int bookId) throws RemoteException {
// 根据ID查找书籍
return mBookList.get(bookId);
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
};
@Override
public void onCreate() {
super.onCreate();
// 初始化数据
mBookList.add(new Book(1, "Android开发艺术探索"));
mBookList.add(new Book(2, "行代码"));
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
5. 在AndroidManifest.xml中声明Service
<service
android:name=".BookManagerService"
android:process=":remote" <!-- 指定在独立进程中运行 -->
android:exported="true">
</service>
6. 客户端绑定服务并调用
public class MainActivity extends AppCompatActivity {
private IBookManager mBookManager;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBookManager = IBookManager.Stub.asInterface(service);
try {
// 调用远程方法
int count = mBookManager.getBookCount();
List<Book> bookList = mBookManager.getBookList();
// 更新UI
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBookManager = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 绑定服务
Intent intent = new Intent(this, BookManagerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
三、AIDL数据类型支持
- 基本数据类型:int, long, char, boolean, double, float, byte, String
- 其他类型:
- CharSequence
- List (元素必须是支持的类型)
- Map (键值必须是支持的类型)
- 实现Parcelable接口的自定义对象
四、AIDL定向Tag
AIDL参数支持三种定向Tag:
in
:输入参数,客户端→服务端out
:输出参数,服务端→客户端inout
:双向参数
void updateBook(in Book book); // 客户端向服务端传递
void getBookInfo(out Book book); // 服务端向客户端返回
void syncBook(inout Book book); // 双向传递
五、AIDL高级特性
1. 回调接口
服务端可以调用客户端的方法:
// IOnNewBookArrivedListener.aidl
interface IOnNewBookArrivedListener {
void onNewBookArrived(in Book newBook);
}
在IBookManager.aidl中添加:
void registerListener(IOnNewBookArrivedListener listener);
void unregisterListener(IOnNewBookArrivedListener listener);
2. 服务端实现回调
private RemoteCallbackList<IOnNewBookArrivedListener> mListeners = new RemoteCallbackList<>();
private Binder mBinder = new IBookManager.Stub() {
// ... 其他方法
@Override
public void registerListener(IOnNewBookArrivedListener listener) {
mListeners.register(listener);
}
@Override
public void unregisterListener(IOnNewBookArrivedListener listener) {
mListeners.unregister(listener);
}
};
// 当有新书到达时通知所有监听者
private void onNewBookArrived(Book book) {
final int N = mListeners.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewBookArrivedListener l = mListeners.getBroadcastItem(i);
try {
l.onNewBookArrived(book);
} catch (RemoteException e) {
e.printStackTrace();
}
}
mListeners.finishBroadcast();
}
3. 客户端实现回调
private IOnNewBookArrivedListener mListener = new IOnNewBookArrivedListener.Stub() {
@Override
public void onNewBookArrived(Book newBook) throws RemoteException {
// 在主线程处理
runOnUiThread(() -> {
// 更新UI显示新书
});
}
};
// 注册监听
try {
mBookManager.registerListener(mListener);
} catch (RemoteException e) {
e.printStackTrace();
}
六、AIDL注意事项
-
线程模型:
- 服务端方法运行在Binder线程池中
- 客户端调用是同步的,会阻塞调用线程
- UI相关操作需要切换到主线程
-
RemoteCallbackList:
- 用于管理跨进程监听器
- 自动处理监听器死亡情况
- 必须配对使用beginBroadcast()和finishBroadcast()
-
异常处理:
- 所有AIDL方法都应处理RemoteException
- 服务端异常会传递到客户端
-
性能考虑:
- 跨进程调用比本地调用慢
- 避免频繁的小数据量调用
- 考虑批量操作减少IPC次数
-
安全性:
- 使用权限验证
- 敏感操作需要检查调用者身份
七、AIDL vs Messenger vs ContentProvider
| 特性 | AIDL | Messenger | ContentProvider |
|-------------|-----------------------|----------------------|----------------------|
| 复杂度 | 高 | 低 | 中 |
| 性能 | 高 | 中 | 低 |
| 数据类型支持 | 丰富 | 简单 | 丰富 |
| 适用场景 | 复杂IPC | 简单消息 | 数据共享 |
| 多线程支持 | 是 | 否 | 是 |
| 回调支持 | 是 | 否 | 有限 |
AIDL适用于需要高性能、复杂交互的场景;Messenger适合简单的消息传递;ContentProvider适合数据共享场景。
八、常见问题解决
-
ClassNotFoundException:
- 确保自定义类实现了Parcelable
- 确保AIDL文件中声明了parcelable
-
TransactionTooLargeException:
- 减少单次传输数据量
- 考虑分批次传输大数据
-
DeadObjectException:
- 服务进程可能已终止
- 需要重新绑定服务
-
SecurityException:
- 检查权限设置
- 确保服务exported属性正确
通过以上,你应该对Android AIDL有了全面的了解。AIDL是Android中实现复杂进程间通信的强大工具,合理使用可以构建出高效、稳定的跨进程应用架构。