如何用UriMatcher匹配带查询参数的Content Provider URI?
嘿,这个问题我之前做Content Provider开发时也踩过坑!首先得明确:UriMatcher只负责匹配URI的路径部分,完全不会处理?后面的查询参数。所以直接用addURI()是没法直接匹配带特定参数的URI的,但有几个实用的解决办法:
方法1:先匹配路径,再检查查询参数
这是最常规也是官方推荐的做法——先用UriMatcher匹配基础路径,比如你已经实现的.../path/#,然后在query()、update()等方法里提取并验证查询参数。
举个代码例子:
// 先定义基础的UriMatcher规则 private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { // 匹配带ID的路径 sUriMatcher.addURI(YOUR_AUTHORITY, "path/#", PATH_WITH_ID); } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { int matchCode = sUriMatcher.match(uri); switch (matchCode) { case PATH_WITH_ID: // 提取查询参数 String arg1 = uri.getQueryParameter("arg1"); String arg2 = uri.getQueryParameter("arg2"); // 验证参数是否符合要求 if ("val1".equals(arg1) && "val2".equals(arg2)) { // 处理符合特定参数的请求 return getFilteredData(uri); } else { // 参数不符合,返回默认结果或抛出异常 return getDefaultData(uri); } // 其他路径匹配的case... default: throw new IllegalArgumentException("无法识别的URI: " + uri); } }
优缺点:简单易实现,符合Content Provider的设计逻辑;但如果有大量不同参数组合的场景,代码会稍显繁琐。
方法2:将查询参数整合到路径中(可控场景)
如果你能控制URI的格式(比如是自己APP内部调用),可以把查询参数转化为路径的一部分,这样就能用UriMatcher的*和#通配符直接匹配了。
比如把.../path/123?arg1=val1&arg2=val2改成.../path/123/arg1/val1/arg2/val2,然后定义匹配规则:
static { // 匹配特定参数值的精确规则 sUriMatcher.addURI(YOUR_AUTHORITY, "path/#/arg1/val1/arg2/val2", PATH_WITH_ID_AND_SPECIFIC_ARGS); // 匹配任意参数值的通用规则 sUriMatcher.addURI(YOUR_AUTHORITY, "path/#/arg1/*/arg2/*", PATH_WITH_ID_AND_ANY_ARGS); }
优缺点:可以直接用UriMatcher完成精确匹配,逻辑更清晰;但只适用于你能修改URI格式的场景,如果是外部调用方固定的URI就没法用。
方法3:自定义匹配逻辑(进阶)
如果上面两种方法都不满足你的需求,可以自己实现一套包含查询参数的匹配逻辑——比如封装一个自定义的匹配方法,先调用原生UriMatcher匹配路径,再额外校验查询参数。
举个简单的实现:
private int customUriMatch(Uri uri) { // 先匹配路径部分 int pathMatch = sUriMatcher.match(uri); if (pathMatch == PATH_WITH_ID) { // 校验特定参数 String arg1 = uri.getQueryParameter("arg1"); if ("val1".equals(arg1)) { return PATH_WITH_ID_AND_ARG1_VAL1; } // 可以添加更多参数组合的判断 } // 不满足参数条件时返回基础路径的匹配码 return pathMatch; }
然后在Content Provider的方法里用这个自定义方法替代原生的match()即可。
总的来说,方法1是最通用的解决方案,因为查询参数的设计初衷就是用来过滤数据,而非区分不同的资源类型;如果是要区分资源类型,更适合用路径来定义,而非查询参数。
内容的提问来源于stack exchange,提问作者rothloup

