ContentProvider 的 URI 匹配机制主要通过 UriMatcher 类实现,用于根据 URI 路径决定如何处理数据请求。以下是其核心机制和用法:
URI 结构
ContentProvider 的 URI 通用格式为:
text
content://<authority>/<path>/<id>?<query>
- authority :ContentProvider 的唯一标识,需与
AndroidManifest.xml
中声明的android:authorities
一致。 - path :标识数据表或资源类型(如
users
)。 - id :可选,标识特定记录(如
123
)。 - query:可选参数,不影响 URI 匹配,但用于数据过滤。
UriMatcher 的使用步骤
-
定义匹配规则 使用通配符
#
(数字)和*
(任意字符)注册 URI 模式:javaprivate static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); // 匹配常量 private static final int CODE_USERS = 1; private static final int CODE_USER_ID = 2; private static final int CODE_PRODUCTS = 3; static { sUriMatcher.addURI("com.example.provider", "users", CODE_USERS); // 匹配 users 表 sUriMatcher.addURI("com.example.provider", "users/#", CODE_USER_ID); // 匹配特定用户 sUriMatcher.addURI("com.example.provider", "products", CODE_PRODUCTS); // 匹配 products 表 }
-
在 ContentProvider 中处理匹配结果 根据 URI 匹配的返回值,执行对应操作:
java@Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { switch (sUriMatcher.match(uri)) { case CODE_USERS: // 查询所有用户 return queryAllUsers(); case CODE_USER_ID: // 提取 ID 并查询单条记录 String id = uri.getLastPathSegment(); return queryUserById(id); case CODE_PRODUCTS: // 查询所有商品 return queryAllProducts(); default: throw new IllegalArgumentException("Unknown URI: " + uri); } }
通配符规则
#
:匹配数字(如users/123
)。*
:匹配任意字符(如path/*
可匹配path/abc
或path/123
)。
匹配优先级
- 精确路径优先于通配符 。例如,若同时注册
users/#
和users/*
,URIusers/123
会优先匹配users/#
。 - 若无匹配项,
UriMatcher.match()
返回UriMatcher.NO_MATCH
,需处理异常。
MIME 类型关联
根据 URI 返回对应的 MIME 类型:
- 多条数据 :
vnd.android.cursor.dir/vnd.<authority>.<path>
- 单条数据 :
vnd.android.cursor.item/vnd.<authority>.<path>
java
@Override
public String getType(Uri uri) {
switch (sUriMatcher.match(uri)) {
case CODE_USERS:
return "vnd.android.cursor.dir/vnd.com.example.provider.users";
case CODE_USER_ID:
return "vnd.android.cursor.item/vnd.com.example.provider.users";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
常见操作示例
- 插入数据 :通常使用基础 URI(如
content://com.example.provider/users
),返回新记录的 URI(如content://com.example.provider/users/456
)。 - 批量更新/删除:通过 URI 是否包含 ID 区分操作范围(更新所有记录或特定记录)。
最佳实践
- URI 定义为常量:避免硬编码,便于维护和跨应用访问。
- 权限控制 :通过
AndroidManifest.xml
的<permission>
标签限制访问权限。 - 参数处理 :利用
Uri
的getQueryParameter()
解析查询参数。
示例场景:处理用户和书籍数据
java
// UriMatcher 注册
sUriMatcher.addURI("com.example.library", "users", CODE_USERS);
sUriMatcher.addURI("com.example.library", "users/#", CODE_USER_ID);
sUriMatcher.addURI("com.example.library", "books", CODE_BOOKS);
// 在 query() 中
switch (sUriMatcher.match(uri)) {
case CODE_USERS:
return db.query("users", ...);
case CODE_USER_ID:
String userId = uri.getLastPathSegment();
return db.query("users", "id=?", new String[]{userId}, ...);
case CODE_BOOKS:
return db.query("books", ...);
}