Android的UriMatcher存在问题

时间:2011-02-17 14:17:12

标签: 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);

}

添加另一个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)无法识别。我很确定问题不在我的代码中(我已经设法创建一个有效的ContentProvider利用Uris并在此问题之前调试它们的所有问题),而是在Android中使用Uri匹配的问题

更新:

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

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

4 个答案:

答案 0 :(得分:35)

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

  1. UriMatcher尝试将整个Uri与模式进行匹配。与java.util.regex.Matcher的matches()方法非常相似,只有当整个区域序列与匹配器的模式匹配时才返回true(与对部分匹配返回true的find()方法相比)。
  2. 通配符仅应用于一个路径段,这意味着*或SDS2MobileDemo / *将永远不会与SDS2MobileDemo / reverse / C_1匹配,但* / * / *或* / * / C_1将会匹配。
  3. 找到路径段的匹配后,它将找不到该特定路径段的任何替代匹配。
  4. 以下是使用以下网址的一些示例: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
    }
    

    如果你颠倒了(伪)代码的顺序:

    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相匹配,真的无法确定正确的解决方案是什么。

答案 1 :(得分:2)

哼哼......啊错字?似乎在 / reverse /

之后有一些空格
uriMatcher.addURI(JobMetaData.AUTHORITY, "*/reverse/*", REVERSE_URI);

应该有效

修改

以下示例有效,请尝试使用您的值并检查LogCat窗口是否有警告

检查JobMetaData.AUTHORITY中的值。

public static final String PROVIDER ="org.dummy.provider" ;

public static void doTest() 
{
  testUri("content://"+PROVIDER +"/test/reverse/xb32") ; 
  testUri("content://"+PROVIDER +"/JobNames/YES/") ;
}

private static void testUri(String pStr) 
{
    Uri uri = Uri.parse(pStr); 
    Log.w("Test", "uri = " + pStr) ;    
    int result = uriMatcher.match(uri) ;    
    Log.w("Test", "result = " + result) ;  
    List<String> list = uri.getPathSegments() ;   

    for (int i = 0  ; i < list.size() ; i++)
      Log.w("Test", "Segment" + i + " = " + uri.getPathSegments().get(i)) ;   
}

答案 2 :(得分:1)

我们可以使用Regex作为环顾解决方案。

这是表达式

https?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?

它应该有用!

答案 3 :(得分:0)

我刚遇到UriMatcher问题并解决了它。确保你总是把外卡完全匹配。如果你没有,UriMatcher代码会沿着通配符路径向下移动,如果它选择了错误的路径,则不会返回。

不幸的是,我没有看到你的情况究竟出了什么问题。我会尝试将JOBNAME_COLLECTION_URI移到最顶层或将其删除;我想知道这是否会导致问题。