Android的UriMatcher存在问题

Lun*_*box 18 android uri android-contentprovider

在对我之前的一个问题的回答中,有人表示Android类UriMatcher中存在一些固有的缺陷(缺乏一个更好的词).任何人都可以通过UriMatcher查明已知问题吗?我正在设计一个依赖于UriMatcher的内容提供程序来正确匹配我的Uris(而不是我猜错了).是否存在已知问题的解决方法?或者是否有更好的匹配Uris的策略?

例:

这是我的UriMatcher的代码设置

private static final int MEMBER_COLLECTION_URI = 1;
private static final int MEMBER_SINGLE_URI = 2;
private static final int SUBMATERIAL_COLLECTION_URI = 3;
private static final int SUBMATERIAL_SINGLE_URI = 4;
private static final int JOBNAME_COLLECTION_URI = 5;
private static final int JOBNAME_SINGLE_URI = 6;
private static final int ALL_MEMBERS_URI = 7;
private static final int ALL_SUBMATERIAL_URI = 8;

static
{
        //return the job and fab for anything matching the provided jobName
        // JobNames/jobName
        uriMatcher.addURI(JobMetaData.AUTHORITY, "JobNames/*/",
                          JOBNAME_SINGLE_URI);
        //return a collection of members
        // jobName/member/attribute/value
        uriMatcher.addURI(JobMetaData.AUTHORITY, "*/member/*/*/",
                          MEMBER_COLLECTION_URI);
        //return a single member
        // jobName/member/memberNumber
        uriMatcher.addURI(JobMetaData.AUTHORITY, "*/member/*/",
                          MEMBER_SINGLE_URI);
        //return a collection of submaterial
        // jobName/submaterial/attribute/value
        uriMatcher.addURI(JobMetaData.AUTHORITY, "*/submaterial/*/*",
                          SUBMATERIAL_COLLECTION_URI);
        //return a single piece of submaterial
        // jobName/submaterial/GUID
        //GUID is the only way to uniquely identify a piece of submaterial    
        uriMatcher.addURI(JobMetaData.AUTHORITY, "*/submaterial/*",
                          SUBMATERIAL_SINGLE_URI);
        //Return everything in the member and submaterial tables
        //that has the provided attribute that matches the provided value
        // jobName/attribute/value
        //not currently used
        uriMatcher.addURI(JobMetaData.AUTHORITY, "JobNames/",
                          JOBNAME_COLLECTION_URI);
        //return all members in a job
        uriMatcher.addURI(JobMetaData.AUTHORITY, "*/members/",
                          ALL_MEMBERS_URI);

}
Run Code Online (Sandbox Code Playgroud)

添加另一个Uri:

private static final int MEMBER_COLLECTION_URI = 1;
private static final int MEMBER_SINGLE_URI = 2;
private static final int SUBMATERIAL_COLLECTION_URI = 3;
private static final int SUBMATERIAL_SINGLE_URI = 4;
private static final int JOBNAME_COLLECTION_URI = 5;
private static final int JOBNAME_SINGLE_URI = 6;
private static final int ALL_MEMBERS_URI = 7;
private static final int ALL_SUBMATERIAL_URI = 8;
//ADDITIONAL URI
private static final int REVERSE_URI = 9;

static
{
        //return the job and fab for anything matching the provided jobName
        // JobNames/jobName
        uriMatcher.addURI(JobMetaData.AUTHORITY, "JobNames/*/",
                          JOBNAME_SINGLE_URI);
        //return a collection of members
        // jobName/member/attribute/value
        uriMatcher.addURI(JobMetaData.AUTHORITY, "*/member/*/*/",
                          MEMBER_COLLECTION_URI);
        //return a single member
        // jobName/member/memberNumber
        uriMatcher.addURI(JobMetaData.AUTHORITY, "*/member/*/",
                          MEMBER_SINGLE_URI);
        //return a collection of submaterial
        // jobName/submaterial/attribute/value
        uriMatcher.addURI(JobMetaData.AUTHORITY, "*/submaterial/*/*",
                          SUBMATERIAL_COLLECTION_URI);
        //return a single piece of submaterial
        // jobName/submaterial/GUID
        //GUID is the only way to uniquely identify a piece of submaterial    
        uriMatcher.addURI(JobMetaData.AUTHORITY, "*/submaterial/*",
                          SUBMATERIAL_SINGLE_URI);
        //Return everything in the member and submaterial tables
        //that has the provided attribute that matches the provided value
        // jobName/attribute/value
        //not currently used
        uriMatcher.addURI(JobMetaData.AUTHORITY, "JobNames/",
                          JOBNAME_COLLECTION_URI);
        //return all members in a job
        uriMatcher.addURI(JobMetaData.AUTHORITY, "*/members/",
                          ALL_MEMBERS_URI);
        //ADDITIONAL URI
        uriMatcher.addURI(JobMetaData.AUTHORITY, "*/reverse/*",
                          REVERSE_URI);

}
Run Code Online (Sandbox Code Playgroud)

最后一个Uri无法识别使用:uriMatcher.match(uri)

在上一个问题(前面提到过)中,建议我将违规的Uri移到UriMatcher.put(String,int)调用的顶部.这解决了以前的问题(让我口中的味道很糟糕).使用此代码尝试相同的解决方案会导致当前的第一个Uri(JOBNAME_SINGLE_URI)无法识别.我很确定问题不在我的代码中(我已经设法创建一个有效的ContentProvider利用Uris并在此问题之前调试它们的所有问题),而是在Android中使用Uri匹配的问题.

更新:

public final static String AUTHORITY = "dsndata.sds2mobile.jobprovider";
Run Code Online (Sandbox Code Playgroud)

示例Uri:
content://dsndata.sds2mobile.jobprovider/SDS2MobileDemo/reverse/C_1

Ema*_*lin 35

有三个规则没有详细记录,但对于理解UriMatcher的匹配机制至关重要:

  1. UriMatcher试图将整个Uri与模式相匹配.与java.util.regex.Matcher的matches()方法非常相似,只有当整个区域序列与匹配器的模式匹配时才返回true(与对部分匹配返回true的find()方法相比).
  2. 通配符仅应用于一个路径段,这意味着*或SDS2MobileDemo/*将永远不会与SDS2MobileDemo/reverse/C_1匹配,但*/*/*或*/*/C_1将匹配.
  3. 一旦找到路径段的匹配项,它就不会找到该特定路径段的任何替代匹配项.

以下是使用以下网址的一些示例:content://dsndata.sds2mobile.jobprovider/SDS2MobileDemo/reverse/C_1

前两条规则很容易理解:

  • SDS2MobileDemo/*/*将匹配
  • */reverse/*将匹配
  • */*将不匹配,因为它只匹配两个路径段
  • SDS2MobileDemo将不匹配,因为它只匹配一个路径段

第三条规则有点难以理解.如果您按照这个确切的顺序添加以下Uris:

  • */错/ C_1
  • SDS2MobileDemo /反向/ C_1

然后它将找不到匹配,因为它转换为以下(伪)代码:

if ("*".matches("SDS2MobileDemo")) {    
    // tries to match the other parts but fails    
}
else if ("SDS2MobileDemo".matches("SDS2MobileDemo")) {
    // will never be executed
}
Run Code Online (Sandbox Code Playgroud)

如果颠倒顺序,(伪)代码变为:

if ("SDS2MobileDemo".matches("SDS2MobileDemo")) {    
    // tries to match the other parts and succeeds    
}    
else if ("*".matches("SDS2MobileDemo")) {    
    // will never be executed    
}
Run Code Online (Sandbox Code Playgroud)

现在就原来的问题而言.SDS2MobileDemo/reverse/C_1将匹配*/reverse/*,但不会匹配例如JobNames/reverse/C_1,因为那个将沿着JobNames/*路径向下...同样很清楚将*/reverse/*移动到顶部isn这是解决方案,因为所有其他不以*开头的模式将不再匹配.只要不知道哪种模式应与哪种Uris相匹配,真正无法确定正确的解决方案是什么.