developer.android.google.cn/guide/compo…
一、AIDL 核心知识点
1. 基础类型支持
| 类型 | 说明 | 注意事项 |
|---|---|---|
| 所有基本类型 | int, long, char, boolean, float, double, byte | 不支持 short(可用int替代) |
| String & CharSequence | UTF-8 字符串 | 跨进程传递自动转换 |
| ArrayList | 动态数组 | 实际接收类型固定为 ArrayList,元素必须是 AIDL 支持类型 |
| HashMap | 键值对集合 | 实际接收类型固定为 HashMap,Key/Value 都需 AIDL 支持 |
| Parcelable 对象 | 实现 Parcelable 接口的对象 | 包括 Android 的 Bundle |
| AIDL 接口 | 其他 AIDL 定义的接口 | 不支持普通 Java 接口 |
重要限制:
- 不支持泛型声明(如
Map<String,Integer>) - 集合嵌套时,所有层级元素都需符合 AIDL 类型要求
- 文件描述符(FileDescriptor) 需使用 @fd 注解
2. Parcelable 对象实现
// Book.java
public class Book implements Parcelable {
private String title;
private double price;
protected Book(Parcel in) {
title = in.readString();
price = in.readDouble();
}
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];
}
};
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(title);
dest.writeDouble(price);
}
@Override
public int describeContents() {
return 0;
}
//省略get/set方法
}
// Book.aidl
parcelable Book;
二、参数修饰符详解
| 修饰符 | 数据流向 | 服务端获取对象数据 | 修改同步到客户端 | 适用场景 |
|---|---|---|---|---|
in | Client → Server | ✔️ | ✘ | 只读输入参数 |
out | Client ← Server | ✘ | ✔️ | 输出型参数 |
inout | Client ↔ Server | ✔️ | ✔️ | 双向参数 |
规则:
- 基本类型和
String/CharSequence默认in,可不显式声明``` - 所有非基本类型参数 必须 明确指定 in/out/inout
示例代码
// 定义 Parcelable 对象
parcelable UserData;
interface IUserService {
// in 示例:传递用户ID(基本类型)
UserData getUser(in long userId);
// out 示例:获取服务状态(对象)
void getServiceStatus(out Bundle status);
// inout 示例:更新用户信息(双向)
void updateUser(inout UserData user);
// String 默认 in(可不声明)
void logEvent(String eventName);
}
oneway 方法修饰符
核心特性
oneway void asyncTask(in int param);
| 特性 | 说明 |
|---|---|
| 异步调用 | 客户端立即返回,不阻塞 |
| 无返回值 | 必须声明为 void |
| 参数限制 | 所有参数需为基本类型或 in 修饰 |
| 执行顺序 | 不保证调用顺序 |
| 执行线程 | 服务端在 独立Binder线程 执行 |
适用场景
- 不需要返回结果的操作(如日志记录、通知)
- 耗时操作但不需要客户端等待(如数据备份)
- 高频率调用的非关键操作
禁止场景
// 错误示例1:有返回值
oneway int getStatus(); // 编译错误!
// 错误示例2:使用 out 参数
oneway void processData(out Result result); // 编译错误!
三、AIDL 接口使用
1. AIDL 接口作为参数
// IOperationCallback.aidl
interface IOperationCallback {
oneway void onSuccess(in String result);
oneway void onFailure(in String error);
}
// IDataService.aidl
import com.example.IOperationCallback;
interface IDataService {
void fetchData(in String query, in IOperationCallback callback);
}
2. 服务端实现
public class DataServiceImpl extends IDataService.Stub {
@Override
public void fetchData(String query, IOperationCallback callback) {
try {
String result = processQuery(query); // 耗时操作
callback.onSuccess(result);
} catch (Exception e) {
callback.onFailure(e.getMessage());
}
}
}
3. 客户端使用
// 创建回调实现
private IOperationCallback callback = new IOperationCallback.Stub() {
@Override
public void onSuccess(String result) {
runOnUiThread(() -> updateUI(result));
}
@Override
public void onFailure(String error) {
runOnUiThread(() -> showError(error));
}
};
// 调用远程服务
dataService.fetchData("search_term", callback);
四、死亡通知机制(服务异常处理)
1. 注册死亡通知
private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
Log.w(TAG, "远程服务已终止");
// 1. 清理资源
mService = null;
// 2. 尝试重新连接
reconnectToService();
}
};
private void bindService() {
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IDataService.Stub.asInterface(service);
try {
// 注册死亡通知
service.linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
2. 处理服务崩溃
@Override
protected void onDestroy() {
super.onDestroy();
if (mService != null) {
mService.asBinder().unlinkToDeath(deathRecipient, 0);
unbindService(connection);
}
}
private void reconnectToService() {
unbindService(connection); // 先解绑旧连接
new Handler(Looper.getMainLooper()).postDelayed(() -> {
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}, 3000);
}
四、综合示例:图书管理系统
1. AIDL 文件定义
// IBookManager.aidl
import com.example.Book;
import com.example.IBookEventListener;
interface IBookManager {
// 添加图书(inout 双向修改)
void addBook(inout Book book);
// 获取图书列表
List<Book> getBooks();
// 注册事件监听器
void registerListener(in IBookEventListener listener);
// 注销事件监听器
void unregisterListener(in IBookEventListener listener);
// 异步添加图书(oneway)
oneway void addBookAsync(in Book book);
}
// IBookEventListener.aidl
oneway interface IBookEventListener {
void onBookAdded(in Book newBook);
void onBookRemoved(in String bookTitle);
}
2. 服务端关键实现
public class BookManagerService extends Service {
private final CopyOnWriteArrayList<Book> mBooks = new CopyOnWriteArrayList<>();
private final RemoteCallbackList<IBookEventListener> mListeners = new RemoteCallbackList<>();
private final IBinder mBinder = new IBookManager.Stub() {
@Override
public void addBook(inout Book book) {
book.setPrice(book.getPrice() * 0.9); // 打9折
mBooks.add(book);
notifyBookAdded(book);
}
@Override
public List<Book> getBooks() {
return new ArrayList<>(mBooks);
}
@Override
public void registerListener(IBookEventListener listener) {
if (listener != null) {
mListeners.add(listener);
}
}
@Override
public void unregisterListener(IBookEventListener listener) {
mListeners.remove(listener);
}
@Override
public void addBookAsync(Book book) {
// 后台处理
new Thread(() -> {
processBookInBackground(book);
mBooks.add(book);
notifyBookAdded(book);
}).start();
}
};
private void notifyBookAdded(Book book) {
int count = mListeners.beginBroadcast();
for (int i = 0; i < count; i++) {
try {
mListeners.getBroadcastItem(i).onBookAdded(book);
} catch (RemoteException e) { /* 忽略断开连接 */ }
}
mListeners.finishBroadcast();
}
}
3. 客户端完整实现
public class MainActivity extends AppCompatActivity {
private IBookManager mBookManager;
private final IBookEventListener mEventListener = new IBookEventListener.Stub() {
@Override
public void onBookAdded(Book newBook) {
runOnUiThread(() -> showToast("新书添加: " + newBook.getTitle()));
}
@Override
public void onBookRemoved(String bookTitle) {
runOnUiThread(() -> showToast("书籍移除: " + bookTitle));
}
};
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBookManager = IBookManager.Stub.asInterface(service);
try {
// 注册死亡通知
service.linkToDeath(() -> reconnectService(), 0);
// 注册事件监听器
mBookManager.registerListener(mEventListener);
// 获取初始数据
loadInitialBooks();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBookManager = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindBookManagerService();
}
private void bindBookManagerService() {
Intent intent = new Intent(this, BookManagerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
private void addNewBook() {
Book newBook = new Book("Android进阶指南", 99.9);
if (mBookManager != null) {
try {
// 使用inout参数获取修改后的对象
mBookManager.addBook(newBook);
Log.d("BookInfo", "最终价格: " + newBook.getPrice()); // 显示折扣价
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
if (mBookManager != null) {
mBookManager.unregisterListener(mEventListener);
mBookManager.asBinder().unlinkToDeath(null, 0);
}
} catch (RemoteException e) {
e.printStackTrace();
}
unbindService(mConnection);
}
}
五、AIDL 最佳实践
-
线程管理
- 服务端方法运行在 Binder 线程池(非 UI 线程)
- 客户端回调运行在 Binder 线程(需切回 UI 线程更新界面)
-
异常处理
try { mRemoteService.sensitiveOperation(); } catch (RemoteException e) { // 处理进程间通信错误 } catch (SecurityException e) { // 处理权限问题 } -
性能优化
- 使用
oneway修饰非关键异步操作 - 避免在 AIDL 方法中进行同步阻塞操作
- 避免在单个调用中传递超过 1MB 数据,大数据传输考虑使用
ContentProvider
- 使用
-
安全机制
<service android:name=".DataService" android:permission="com.example.PERMISSION_ACCESS_DATA"> <intent-filter> <action android:name="com.example.DATA_SERVICE"/> </intent-filter> </service>// 服务端添加权限验证 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) { if (!checkCallingPermission("com.example.PERMISSION_ACCESS_DATA")) { throw new SecurityException("Permission denied"); } return super.onTransact(code, data, reply, flags); } -
版本兼容
- 使用
@Nullable和@NonNull注解 - 新增方法时考虑向后兼容
- 使用版本号管理接口变更
// 接口版本管理 interface IBookManager { @VERSION(version = 2) // 标注接口版本 List<Book> getBooks(); } - 使用