一、AIDL 基本概念
1. 定义与作用
AIDL (Android Interface Definition Language) 是 Android 的接口定义语言,主要用于解决跨进程通信(IPC)问题。它允许不同应用的组件在不同的进程间相互通信。
2. 核心特点
特性 | 说明 |
---|---|
跨进程调用 | 支持不同进程间的方法调用 |
同步通信 | 默认同步调用(客户端会阻塞) |
自动序列化 | 自动处理参数和返回值的序列化 |
多线程支持 | 服务端方法可能被多个线程同时调用 |
3. 适用场景
-
需要跨应用共享功能
-
应用内多进程间通信
-
需要后台服务长时间运行
-
实现远程方法调用(RPC)
二、AIDL 使用全流程
1. 创建 AIDL 文件
在 src/main/aidl/
目录下创建接口文件:
// IMyService.aidl
package com.example.service;
// 声明接口
interface IMyService {
// 基本类型参数
int add(int a, int b);
// 自定义对象参数(需实现Parcelable)
void registerListener(IMyListener listener);
void unregisterListener(IMyListener listener);
// in/out/inout 参数定向标记
void modifyData(inout Data data);
}
// 回调接口定义
interface IMyListener {
void onDataChanged(in Data newData);
}
// 自定义Parcelable类型
parcelable Data;
2. 实现 Parcelable 对象
// Data.java
public class Data implements Parcelable {
private int value;
private String info;
// 必须实现的CREATOR
public static final Creator<Data> CREATOR = new Creator<Data>() {
@Override
public Data createFromParcel(Parcel in) {
return new Data(in);
}
@Override
public Data[] newArray(int size) {
return new Data[size];
}
};
protected Data(Parcel in) {
value = in.readInt();
info = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(value);
dest.writeString(info);
}
@Override
public int describeContents() {
return 0;
}
}
3. 实现 Service
public class MyService extends Service {
private final IMyService.Stub binder = new IMyService.Stub() {
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public void registerListener(IMyListener listener) {
// 实现监听器注册
}
@Override
public void unregisterListener(IMyListener listener) {
// 实现监听器注销
}
@Override
public void modifyData(Data data) {
data.setValue(data.getValue() * 2);
}
};
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
4. 客户端绑定服务
public class MainActivity extends Activity {
private IMyService myService;
private boolean isBound = false;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService = IMyService.Stub.asInterface(service);
isBound = true;
try {
int result = myService.add(5, 3); // 调用远程方法
Log.d("AIDL", "5 + 3 = " + result);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
myService = null;
isBound = false;
}
};
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, MyService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (isBound) {
unbindService(connection);
isBound = false;
}
}
}
三、高级特性与最佳实践
1. 参数定向标记
标记 | 说明 | 性能影响 |
---|---|---|
in | 数据从客户端流向服务端 | 仅序列化一次 |
out | 数据从服务端流向客户端 | 仅反序列化一次 |
inout | 双向数据流 | 序列化和反序列化各一次 |
使用建议:
-
优先使用
in
标记 -
只在需要时使用
inout
-
避免对大对象使用
inout
2. 异常处理
try {
myService.someMethod();
} catch (RemoteException e) {
// 处理IPC通信失败
Log.e("AIDL", "Remote call failed", e);
} catch (SecurityException e) {
// 处理权限问题
Log.e("AIDL", "Permission denied", e);
}
3. 线程安全考虑
-
服务端方法可能被多个线程同时调用
-
需要自行实现同步机制
private final Object lock = new Object(); @Override public void modifyData(Data data) { synchronized (lock) { // 线程安全操作 } }
4. 回调接口实现
// 客户端实现回调接口
private IMyListener listener = new IMyListener.Stub() {
@Override
public void onDataChanged(Data newData) {
runOnUiThread(() -> {
// 更新UI
});
}
};
// 注册回调
myService.registerListener(listener);
四、跨应用通信实现
1. 服务端配置
<!-- AndroidManifest.xml -->
<service
android:name=".MyService"
android:exported="true"
android:permission="com.example.service.PERMISSION">
<intent-filter>
<action android:name="com.example.service.MyService"/>
</intent-filter>
</service>
2. 客户端绑定
Intent intent = new Intent();
intent.setAction("com.example.service.MyService");
intent.setPackage("com.example.service"); // 显式指定包名
bindService(intent, connection, Context.BIND_AUTO_CREATE);
3. 权限声明
<!-- 服务端声明权限 -->
<permission
android:name="com.example.service.PERMISSION"
android:protectionLevel="signature"/>
<!-- 客户端申请权限 -->
<uses-permission android:name="com.example.service.PERMISSION"/>
五、性能优化建议
-
减少IPC调用次数
-
批量操作代替多次调用
-
使用
in
参数减少数据拷贝
-
-
异步调用模式
// 服务端接口添加异步方法 void getDataAsync(IMyDataCallback callback); // 回调接口 interface IMyDataCallback { void onDataReady(in Data data); }
-
对象池技术
-
重用Parcelable对象
-
避免频繁创建对象
-
-
选择合适的IPC方式
场景 推荐方案 简单数据 Intent/Bundle 结构化数据 ContentProvider 高频调用 AIDL 大数据传输 Messenger/Socket
六、常见问题解决方案
1. ClassNotFoundException
-
问题:找不到Parcelable类
-
解决:
-
确保AIDL文件和Java类在相同包
-
在AIDL中正确定义
parcelable
声明
-
2. TransactionTooLargeException
-
问题:传输数据超过1MB限制
-
解决:
-
减少单次传输数据量
-
改用文件共享或ContentProvider
-
3. 回调不触发
-
问题:客户端回调未执行
-
检查:
-
是否正确注册/注销监听器
-
服务端是否持有强引用导致内存泄漏
-
4. 权限拒绝
-
问题:SecurityException
-
解决:
-
检查权限声明
-
确保客户端和服务端使用相同签名
-
通过掌握这些AIDL的核心概念和实用技巧,您可以构建高效的跨进程通信方案,解决Android开发中的复杂进程间通信需求。