I would like to access the content provider using URI, which is of the following form.
sUriMatcher.addURI("org.abcd.providers.contentprovider", "bookmarks", 1)
So, can I access it using the URI, "content://org.abcd.providers.contentprovider/bookmarks" ? What does the value "1" mean? How do I query the provider of this type, Thanks in advance.
The "1" is used internally in the ContentProvider. Its used to associate an URI with an number. Handy for using in a switch statement.
Why not using String matching? Well, an URI might have variable parts. For example "content://my.provider/bank/customer/2". The 2 is the Id of the customer. Or "content://my.provider/location/42/name". The variable part here is the 42. String matching goes out of control here. The UriMatcher on the other hand is able to match example 1 with addURI("my.provider", "bank/customer/#", 1) and example 2 with addURI("my.provider", "location/#/name",2). When we ask a configured UriMatcher to match a URI it returns the number associated with the matching URI.
But we are going out of track here. The number is not relevant to you as a consumer. You can query the provider with the context method 'getContentResilver().query(content://org.abcd.providers.contentprovider/bookmarks, /*other args */)'. See the documentation for more infos.
But you can only talk to the provider if its exported (nothing you can do about it) or it requires permissions that your application has. This includes no permissions at all.
Related
I am writing a content provider and I'm trying to match URIs using UriMatcher. I've already written a few matchers ending either in a ...path/ or .../path/# and that works well.
However, my next step is to start using URIs that include arguments in the query - i.e. .../path/#?arg1=val1,arg2=val2, etc. How do I match the URI against that? According to the addURI() documentation, it only accepts "*" and "#" as wildcards, for any text or numbers, respectively. How do I match against a particular pattern of arguments? Or am I supposed to only match the static part of the URI, and then parse the arguments in the query() method in my content provider?
The reason I'd rather match than parse is because the number of arguments supplied in a valid query can change - i.e. '.../path?arg1=val1is a valid query, and so is '.../path?arg1=val1,arg2=val2. I'd rather not have to write "if arg1 exists, then , if arg1 and arg2 exists, then , etc etc" in my content provider's query function. It can get complex quickly, and it seems a URI matcher would help simplify the code a lot.
I have a file system management app, and I am sharing all types of files with external 3rd party applications using a content provider.
My question is:
What should implementations for #getType() and #getStreamTypes() in content provider look like?
Thanks for all the responses.
See docs for ContentProvider
getType (Uri uri)
Implement this to handle requests for the MIME type of the data at the given URI. The returned MIME type should start with vnd.android.cursor.item for a single record, or vnd.android.cursor.dir/ for multiple items.
getStreamTypes (Uri uri, String mimeTypeFilter)
Called by a client to determine the types of data streams that this content provider supports for the given URI. The default implementation returns null, meaning no types. If your content provider stores data of a particular type, return that MIME type if it matches the given mimeTypeFilter. If it can perform type conversions, return an array of all supported MIME types that match mimeTypeFilter.
To be RESTful, the URI to get the comments for a post, should be something like:
posts/#/comments
Where # is the post id that will change depending on which post your are interested in.
I want to apply some convention when designing the content URI of my content provider. The question is, how is the user of the content provider expected to construct such a URI in an elegant way?
A workable solution is :
//in PostProvider
public static URI CONTENTS_URI_POSTS = Uri.parse("content://" + AUTHORITY + "/posts");
public static String COMMENTS = "comments";
Then the user will use Uri.builder to combine CONTENTS_URI_POSTS + id + COMMENTS. However, this method exposes the details on how to construct a URI.
To hide the details, maybe I could add a method:
public static URI buildContentUriToGetPostComments(int post_id);
Any better idea? Thanks!
You could use different paths for posts and their comments:
content://<authority>/posts/#<post-id>
content://<authority>/comments/#<post-id>
This way you have an URI which looks more conventional and its simpler to handle in the content provider, you do not need to parse the URI but a standard UriMatcher will do.
Not to bring up something old, but I am having trouble implementing this one-to-many relationship as well... If I follow Stefans approach:
content://<authority>/comments/#<post-id>
What if I later want to add a URI to get a specific comment by id?
content://<authority>/comments/#<comment-id>
The above would create an identical match to the previous URI.
In my case, I tried to resolve this by using
content://<authority>/posts/comments/#<post-id>
However, this solution can cause problems. For example, if I want to load a cursor using both:
content://<authority>/comments/ (all comments)
content://<authority>/posts/comments/#<post-id> (comments by post)
and insert a comment using:
content://<authority>/comments
Not all users of the ContentProvider will be notified, as the URI pattern doesn't match.
To solve this, I make sure that my ContentProvider calls notifyChange with the appended ID to BOTH of the 'get all' URI AND the 'get by post id' URI... this is just one solution.
Any drawbacks to implementing it this way? In hindsight it would probably be easier to just rely on the user setting the foreign key in the selection string of the ContentProvider query... but like pierr I wanted to implement it as a single URI.
I have very basic understanding problem of Content types.
I went through lot of examples and text explaining the above term, but still have some basic understanding problem. Can some clarify me please.
In the android notepad example, and many others, it is mentioned vnd.android.cursor.dir/ resolves to a list of items in a directory and vnd.android.cursor.item/ refers to specific item in a directory.
Is this vnd.android.cursor.dir some standard constant defined by android. Where did this come from?, or can i change it like
vn.com.android.myexample.dir/
How is this even resolved and what is its purpose, why not use the full CONTENT_URI?
Sorry, i'm totally lost, and don't understand this.
Documentation: https://developer.android.com/guide/topics/providers/content-provider-basics#MIMETypeReference
The MIME types returned by ContentProvider.getType have two distinct parts:
type/subType
The type portion indicates the well known type that is returned for a given URI by the ContentProvider, as the query methods can only return Cursors the type should always be:
vnd.android.cursor.dir for when you expect the Cursor to contain
0 through infinity items
or
vnd.android.cursor.item for when you expect the Cursor to contain
1 item
The subType portion can be either a well known subtype or something unique to your application.
So when using a ContentProvider you can customize the second subType portion of the MIME type, but not the first portion. e.g a valid MIME type for your apps ContentProvider could be:
vnd.android.cursor.dir/vnd.myexample.whatever
The MIME type returned from a ContentProvider can be used by an Intent to determine which activity to launch to handle the data retrieved from a given URI.
Where did this come from?, or can I change it like vn.com.android.myexample.dir/
No, because "vnd" stands for vendor in MIME Registration trees, android in this case.
Is it possible (or recommended) to pass parameters to content providers via URIs in Android, similar to how web addresses use them? That is to say, can I use name/value pairs in content:// URIs?
For example, I have a search provider that can search based on names. I pass it a URI like this:
content://com.example.app/name/john
That would return anyone with "john" in their names, including John, Johnathon, Johnson, etc.
I want to have the option (but not requirement) to search by exact names and not find partial matches. I was thinking of doing something like this:
content://com.example.app/name/john?exact=true
That would tell the search provider to only return names that exactly match "John." But I haven't seen any other examples of parameters used like this within Android. Is there a better way? What am I missing here?
Thanks!
if you want to pass query parameters you can use the appendQueryParameter() method when constructing your URI
LoaderFactory.createCursorLoader(this,
MyProvider.MY_CONTENT_URI.buildUpon().appendQueryParameter(
MyProvider.MY_PARAM_NAME,
myParamValue).build(), projection, null,
null, null);
And then access the param value using the getQueryParameter()
String paramValue = uri.getQueryParameter(MyProvider.MY_PARAM_NAME);
No, as far as I have seen, any parameters get stripped from content provider urls (although I don't know why), I worked around this by adding parameters using a "/" and a certain prefix and parse them out manually, something like this:
content://com.example.app/name/john/paramexact/true