Problems with Android's UriMatcher

前端 未结 4 1174
你的背包
你的背包 2020-12-13 20:36

In an answer to a previous question of mine someone indicated that there is some flakiness (for lack of a better word) inherent in the Android class UriMatcher. Can anyone p

相关标签:
4条回答
  • 2020-12-13 20:49

    We can use Regex as a look around solution.

    Here is the expression

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

    It should work!

    0 讨论(0)
  • 2020-12-13 21:01

    There are three rules that aren't well documented but that are crucial to understanding the matching mechanism of UriMatcher:

    1. UriMatcher tries to match the entire Uri against the pattern. Much like the matches() method of java.util.regex.Matcher that returns true only if the entire region sequence matches the matcher's pattern (compared to the find() method that returns true for partial matches).
    2. Wildcards are applied to one path segment only, meaning * or SDS2MobileDemo/* will never match SDS2MobileDemo/reverse/C_1 but */*/* or */*/C_1 will.
    3. Once it finds a match for a path segment it won't find any alternative match for that particular path segment.

    Here are some examples using the following url: content://dsndata.sds2mobile.jobprovider/SDS2MobileDemo/reverse/C_1

    The first two rules are easy to understand:

    • SDS2MobileDemo/*/* will match
    • */reverse/* will match
    • */* won't match because it matches only two path segments
    • SDS2MobileDemo won't match because it matches only one path segment

    The third rule is a little harder to understand. If you add the following Uris in this exact order:

    • */wrong/C_1
    • SDS2MobileDemo/reverse/C_1

    then it won't find a match because that translates into the following (pseudo) code:

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

    If you reverse the order the (pseudo) code becomes:

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

    Now as far as the original question goes. SDS2MobileDemo/reverse/C_1 will get matched by */reverse/* but not e.g. JobNames/reverse/C_1 because that one will go down the JobNames/* path... Also it's clear that moving */reverse/* to the top isn't the solution because all other patterns not starting with * won't match any more. There's really no telling what the correct solution is as long as it's unknown which patterns should match which Uris.

    0 讨论(0)
  • 2020-12-13 21:01

    I just ran into a UriMatcher problem and solved it. Make sure that you always put wild cards exact matches. If you don', the UriMatcher code goes down the wildcard path and doesn't go back up if it chose the wrong path.

    Unfortunately, I don't see exactly what's wrong in your case. I would try moving JOBNAME_COLLECTION_URI to the very top or removing it; I wonder if that's causing a problem.

    0 讨论(0)
  • 2020-12-13 21:06

    Hum .... Ah typo ? Seems there is some whitespace after /reverse/

    uriMatcher.addURI(JobMetaData.AUTHORITY, "*/reverse/*", REVERSE_URI);
    

    should work

    EDIT

    The example below works, try with your values and check your LogCat Window for warnings

    Check the value in 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)) ;   
    }
    
    0 讨论(0)
提交回复
热议问题