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", ...);
}
相关推荐
BreezeDove6 小时前
【Android】AS项目自动连接mumu模拟器配置
android
乐世东方客8 小时前
备份脚本记录(binlog文件+mysql+mongo)
android·数据库·mysql
私人珍藏库9 小时前
[Android] 视频下载鸟 v20.02 会员
android·人工智能·智能手机·app·工具·多功能
zh_xuan9 小时前
tv浏览网页工具
android·tv浏览网页
Carson带你学Android11 小时前
Compose 终于上线 FlexBox:换行与弹性伸缩 都轻松搞定!
android·composer
私人珍藏库11 小时前
[Android] 三维山水全景地图-3D地形全景观测地图
android·3d·app·工具·软件·多功能
dengyuezhe806011 小时前
《C++ 异常机制与智能指针:从原理到实现》
android·java·c++
Wonderful U12 小时前
Python+Django实战|企业办公用品申领管理系统:物资入库、库存预警、申领审批、归还登记、损耗统计、供应商对账
android·python·django
plainGeekDev12 小时前
网络状态监听 → ConnectivityManager + Flow
android·java·kotlin
楠目12 小时前
CVE-2013-4547 Nginx URI解析漏洞利用总结
android