共计 2478 个字符,预计需要花费 7 分钟才能阅读完成。
背景与需求分析
在 Android 模块化开发中,跨进程通信(IPC)是常见的需求场景。例如:

- 主 App 需要调用支付模块的独立进程
- 多个应用共享用户配置数据
- 需要隔离核心业务逻辑保证安全性
传统的实现方式各有优缺点:
- AIDL:功能强大但实现复杂,需要手动处理线程安全
- Messenger:基于消息队列,不适合高频调用
- SharedPreferences:仅支持基础数据类型,无函数调用能力
ContentProvider 提供了结构化数据共享机制,通过 Binder 底层支持函数调用,是平衡功能与复杂度的理想选择。
核心实现步骤
1. AndroidManifest 配置
<provider
android:name=".MyProvider"
android:authorities="com.example.provider"
android:exported="true"
android:readPermission="com.example.READ_PERMISSION"
android:writePermission="com.example.WRITE_PERMISSION"/>
关键参数说明:
authorities:全局唯一标识符,建议使用包名前缀exported:控制是否允许其他应用访问permission:细粒度的权限控制
2. UriMatcher 路由配置
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {sUriMatcher.addURI("com.example.provider", "user", CODE_USER);
sUriMatcher.addURI("com.example.provider", "book/#", CODE_BOOK);
}
URI 匹配规则:
#:匹配数字*:匹配任意文本
3. 实现 call 方法
@Override
public Bundle call(String method, String arg, Bundle extras) {switch (method) {
case "add":
int result = Integer.parseInt(arg) + extras.getInt("value");
Bundle bundle = new Bundle();
bundle.putInt("result", result);
return bundle;
default:
throw new IllegalArgumentException("Unsupported method:" + method);
}
}
Binder 机制原理:
- 调用请求通过 Binder 驱动转发到服务端
- 服务端在 Binder 线程池处理请求
- 返回数据通过共享内存传递
完整代码示例
Provider 实现类
public class MyProvider extends ContentProvider {
// UriMatcher 初始化...
@Override
public boolean onCreate() {
// 初始化数据库等操作
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {// 实现查询逻辑}
@Override
public Bundle call(String method, String arg, Bundle extras) {// 函数调用实现}
}
客户端调用
Uri uri = Uri.parse("content://com.example.provider/user");
Bundle result = getContentResolver().call(
uri,
"add",
"5",
new Bundle().putInt("value", 3)
);
int sum = result.getInt("result"); // 得到 8
关键问题解决方案
1. 避免 ANR
- 耗时操作移动到工作线程
- 使用
AsyncQueryHandler简化异步查询
2. 权限管理
<!-- 声明自定义权限 -->
<permission
android:name="com.example.READ_PERMISSION"
android:protectionLevel="signature" />
signature级别要求调用方使用相同证书签名
3. 数据类型限制
- 基本类型可直接传递
- 复杂对象需实现
Parcelable接口
性能优化建议
- 批量操作提升效率
ArrayList<ContentProviderOperation> ops = new ArrayList<>();
ops.add(ContentProviderOperation.newInsert(uri).withValues(values1).build());
ops.add(ContentProviderOperation.newUpdate(uri).withValues(values2).build());
getContentResolver().applyBatch(authority, ops);
- 观察者模式实时更新
getContentResolver().registerContentObserver(
uri,
true,
new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {// 数据变化处理}
}
);
总结对比
| 方案 | 适用场景 | 性能开销 |
|---|---|---|
| ContentProvider | 结构化数据共享 | 中等 |
| AIDL | 高频复杂调用 | 较高 |
| Messenger | 简单消息传递 | 低 |
建议尝试实现一个跨进程计数器:
- Provider 端提供
increment方法 - 客户端每次调用累加计数
- 通过 ContentObserver 实现 UI 自动更新
通过这个完整案例,可以深入理解 Android IPC 的核心机制和最佳实践。
正文完
发表至: 移动开发
近三天内
