ContentProvider URI匹配机制详解

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 的使用步骤

  1. 定义匹配规则 使用通配符 #(数字)和 *(任意字符)注册 URI 模式:

    java 复制代码
    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 表
    }
  2. 在 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/*,URI users/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", ...);
}
相关推荐
mmsx1 小时前
Android 防二次打包第一道锁:签名校验与完整性校验
android·kotlin
mmsx1 小时前
Android 混淆不等于安全:二次打包链路完整走一遍
android·kotlin
小宋10213 小时前
Agent轨迹级评测实战:工具选择、预算超限与回归门禁
android·网络·人工智能·回归
墨天梦5 小时前
D05_ViewModel与单向数据流
android·kotlin
蒸鱼Yuzheng6 小时前
Android 构建可复现性:APK 指纹、文件级差异与供应链审计
android·apk·devops·软件供应链·可复现构建
墨天梦8 小时前
D03_Compose列表与稳定身份
android·gitee·kotlin
萌新杰少9 小时前
Kuikly股票查看软件开发体验——SaiRen
android·kotlin·客户端
vilya9 小时前
把 Python 塞进 APK:Chaquopy 打包实践
android·python
用户92817267390169 小时前
Android Compose版本的AI组件库来了。
android·kotlin
知昂七昂9 小时前
00-02:AOSP 源码阅读环境与检索方法论源码剖析(Android 16 / aosp-main)
android