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", ...);
}
相关推荐
赏金术士18 分钟前
第六章:UI组件与Material3主题
android·ui·kotlin·compose
TechMerger2 小时前
Android 17 重磅重构!服役 20 年的 MessageQueue 迎来无锁改造,卡顿大幅优化!
android·性能优化
yuhuofei20214 小时前
【Python入门】Python中字符串相关拓展
android·java·python
dalancon4 小时前
Android Input Spy Window
android
dalancon6 小时前
InputDispatcher派发事件,查找目标窗口
android
我命由我123456 小时前
Android Framework P3 - MediaServer 进程、认识 ServiceManager 进程
android·c语言·开发语言·c++·visualstudio·visual studio·android runtime
天才少年曾牛7 小时前
Android14 新增系统服务后,应用调用出现 “hidden api” 警告的原因与解决方案
android·frameworks
赏金术士7 小时前
Jetpack Compose 底部导航实战教程(完整版)
android·kotlin·compose
随遇丿而安7 小时前
第5周:XML 资源、样式和主题,真正解决的是“页面以后还改不改得动”
android
zh_xuan8 小时前
Android 获取系统内存页大小:sysconf(_SC_PAGESIZE) 与 JNI 实现
android·jni·ndk·内存页大小