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 pinpoint the known issues with UriMatcher? I'm designing a Content Provider that relies on UriMatcher to match my Uris correctly (as opposed to incorrectly I suppose). Are there workarounds to the known issues? Or is there a better strategy for matching Uris?
Example:
Here is the code setting my 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);
}
Add another 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);
}
And the last Uri is not recognized using: uriMatcher.match(uri)
On the previous question (mentioned earlier) it was recommended that I move the offending Uri to the top of the calls to UriMatcher.put(String, int). That solved the previous problem (and left me with a bad taste in my mouth). Trying the same solution with this code results in the current first Uri (JOBNAME_SINGLE_URI) going unrecognized. I'm fairly sure that the issue isn't in my code (I've managed to create a working ContentProvider utilizing Uris and debug all of the problems with them prior to this issue), but rather is an issue with Uri matching in Android.
UPDATE:
public final static String AUTHORITY = "dsndata.sds2mobile.jobprovider";
Sample Uri:
content://dsndata.sds2mobile.jobprovider/SDS2MobileDemo/reverse/C_1
We can use Regex as a look around solution.
Here is the expression
It should work!
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.
There are three rules that aren't well documented but that are crucial to understanding the matching mechanism of UriMatcher:
Here are some examples using the following url: content://dsndata.sds2mobile.jobprovider/SDS2MobileDemo/reverse/C_1
The first two rules are easy to understand:
The third rule is a little harder to understand. If you add the following Uris in this exact order:
then it won't find a match because that translates into the following (pseudo) code:
If you reverse the order the (pseudo) code becomes:
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.
Hum .... Ah typo ? Seems there is some whitespace after /reverse/
should work
EDIT
The example below works, try with your values and check your LogCat Window for warnings
Check the value in JobMetaData.AUTHORITY.