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/abcpath/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> 标签限制访问权限。
  • 参数处理 :利用 UrigetQueryParameter() 解析查询参数。

示例场景:处理用户和书籍数据

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", ...);
}
相关推荐
光影少年5 分钟前
Android和iOS原生开发的基础知识对RN开发的重要性,RN打包发布时原生端需要做哪些配置?
android·前端·react native·react.js·ios
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.11 分钟前
MySQL主从复制实战配置详解,以及企业级相关优化说明
android·mysql·adb
simpleeeeee12 分钟前
安卓开发者应该知道的 10 个安卓性能优化秘诀
android
simpleeeeee15 分钟前
Android 17:API 级别 37 的开发者指南——现在你需要构建什么
android
zhaoyufei13315 分钟前
RK3566 EDP屏幕背光闪修改pwm
android·java
simpleeeeee18 分钟前
Android 17 正在改写规则——以下是每位开发者都需要了解的内容
android
summerkissyou198721 分钟前
Android-Audio-根据音频焦点控制播放
android·audio
brahmsjiang30 分钟前
Java类加载机制解析:从JVM启动到双亲委派,再到Android的特殊实现
android·java·jvm
fire-flyer33 分钟前
ClickHouse系列(九):慢查询、内存 OOM 与稳定性治理
android·clickhouse
SharpCJ9 小时前
Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革
android·ai·aigc