在回答我的上一个问题时,有人指出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);

}

添加另一个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);

}

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

在前面的问题(前面提到)中,建议我将有问题的Uri移到对UriMatcher.put(String,int)的调用的顶部。这样就解决了先前的问题(并使我口中的味道变差了)。使用此代码尝试相同的解决方案将导致无法识别当前的第一个Uri(JOBNAME_SINGLE_URI)。我相当确定问题不在我的代码中(我已经设法使用Uris创建了一个可用的ContentProvider并在此问题之前调试了所有问题),而是与Android中的Uri匹配有关的问题。

更新:
public final static String AUTHORITY = "dsndata.sds2mobile.jobprovider";

样本Uri:
内容://dsndata.sds2mobile.jobprovider/SDS2MobileDemo/reverse/C_1

最佳答案

以下三条规则没有得到很好的记录,但是对于理解UriMatcher的匹配机制至关重要:

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

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

    前两个规则很容易理解:
  • SDS2MobileDemo/*/*将匹配
  • */reverse/*将匹配
  • */*不匹配,因为它仅匹配两个路径段
  • SDS2MobileDemo不匹配,因为它仅匹配一个路径段

  • 第三条规则很难理解。
    如果您按照以下确切顺序添加以下Uris:
  • */错误/C_1
  • SDS2MobileDemo/reverse/C_1

  • 那么它将找不到匹配项,因为它会转换为以下(伪)代码:
    if ("*".matches("SDS2MobileDemo")) {
        // tries to match the other parts but fails
    }
    else if ("SDS2MobileDemo".matches("SDS2MobileDemo")) {
        // will never be executed
    }
    

    如果您颠倒顺序,则(伪)代码将变为:
    if ("SDS2MobileDemo".matches("SDS2MobileDemo")) {
        // tries to match the other parts and succeeds
    }
    else if ("*".matches("SDS2MobileDemo")) {
        // will never be executed
    }
    

    现在,就原始问题而言。
    SDS2MobileDemo/reverse/C_1将通过*/reverse/*进行匹配,但不会匹配。 JobNames/reverse/C_1,因为那将沿着JobNames/*路径...
    同样很明显,将*/reverse/*移到顶部并不是解决方案,因为所有其他非以*开头的模式将不再匹配。
    只要不知道哪种模式应该与哪个Uris匹配,就真的无法确定什么是正确的解决方案。

    10-07 19:16
    查看更多