ContentProvider URI匹配机制详解
ContentProvider 的 URI 匹配机制主要通过 UriMatcher 类实现,用于根据 URI 路径决定如何处理数据请求。以下是其核心机制和用法:
URI 结构
ContentProvider 的 URI 通用格式为:
content://<authority>/<path>/<id>?<query>
- authority:ContentProvider 的唯一标识,需与
AndroidManifest.xml
中声明的android:authorities
一致。 - path:标识数据表或资源类型(如
users
)。 - id:可选,标识特定记录(如
123
)。 - query:可选参数,不影响 URI 匹配,但用于数据过滤。
UriMatcher 的使用步骤
-
定义匹配规则
使用通配符#
(数字)和*
(任意字符)注册 URI 模式:private 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 匹配的返回值,执行对应操作:@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>
@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()
解析查询参数。
示例场景:处理用户和书籍数据
// 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", ...);
}