Android ContentProvider Uri Matching - android

I am trying to create a content provider where the key contains forward slash "/". I searched about it for quite a while but there is no place/example illustrating it.
content://com.lily.provider/items/*
General example, which I understand:
content://com.lily.provider/items/ab
What I want to do: my key is a string with "/"
content://com.lily.provider/items/a/b
where a/b is the item id, which is in the same position as ab.
My question:
will content://com.lily.provider/items/a/b be matched to content://com.lily.provider/items/* ? why is that?
are there any work-around I could use to solve the problem

Will content://com.lily.provider/items/a/b be matched to content://com.lily.provider/items/* ? why is that?
Yes, it will match. The asterisk * means "match any characters, including slashes".
Are there any work-around I could use to solve the problem
If you want to match known prefixes, then you can just add more entries to your URI matcher (in this order):
content://com.lily.provider/items/a/*
content://com.lily.provider/items/b/*
content://com.lily.provider/items/*
If you insist on having slashes in the data, then you should URI-encode slashes that aren't being used as path separators to %2f.
Otherwise, I'm not sure what the problem is. The "/items/a/b" URI will match your original pattern as desired, and then you can parse the path component of the URI as you wish.

Related

RESTFul Android ContentProvider URI

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.

Android CONTENT TYPE - Is vnd.android.cursor.dir some standard constant defined by android?

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.

What is the mimeType attribute in <data> used for?

I really can’t get the meaning of mimeType. I know that it exists so that the getType method in ContentProvider knows what to match with it. But I’m still not sure what it means or how it’s used.
Any ContentProvider usually defines the type of data it handles (e.g. NotePadProvider handles a Notes data type defined in an inner class of NotePad). A MIME type is just a standardized way to define that data type by giving it a unique name. This allows the data type to be communicated to code that works with a ContentProvider in a standardized way.
It also helps a ContentProvider that handles several different types of data to keep things organized, e.g. a RailwayContentProvider might handle trains, stations and tickets and can use the MIME type to tell each one apart.
Why MIME types?
The use of MIME types is a natural consequence when you think about how a ContentProvider is accessed through URIs, i.e. something like an URL on the Internet. Just like on the Internet there are MIME types like text/html for web pages and image/jpeg for .jpg images, Android wants you to define a custom MIME type for any data type your ContentProvider handles.
An example custom MIME type
In the NotePad (linked above) class of the NotePad example project, you'll find:
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";
This field defines a custom MIME type (recognizable by the type/subtype pattern).
Android suggests you use vnd.android.cursor.dir/... as the first part for any kind of "directory listing" (multiple items) and vnd.android.cursor.item/... as the first part for any kind of single item.
For the subtype, it's again suggested to start it with vnd. and then add something like your reverse domain name/package name, e.g. vnd.android.cursor.item/vnd.com.mydomain.myapp.mydata
To avoid all those vnd... strings in your code, there's also some constants in ContentResolver like CURSOR_DIR_BASE_TYPE and CURSOR_ITEM_BASE_TYPE.
Mimetype Multipurpose Internet Mail Extensions is tell you the description of the content
Text in character sets other than ASCII
Non-text attachments
Message bodies with multiple parts
Header information in non-ASCII character sets
and also whether is it Pdf/epub/html/text etc
If you mean mime type its to tell the receiving entity how to interpret a file. Just like you see .txt and know a file is a text file. This way you can serve a file with .anyExtension and have the browser still know it is a .txt

Linkify Android Transform Question

Trying to do something fairly simple.
Taking text like this
User Name: This is a comment I am making
It is in a single TextView. I want to make the User Name a link. I decided that the easiest thing would be to surround the User Name with something like "$#" so it becomes
"$#User Name:$# This is a comment I am making
That way I can use the following regular expression
Pattern userName = Pattern.compile(".*\\$#(.+)\\$#.*");
with Linkify and make it a link. However, clearly I need to remove the delimiters, so the following is the code
title.setText(titleText);
Linkify.TransformFilter transformer = new Linkify.TransformFilter() {
#Override
public String transformUrl(Matcher match, String url) {
return match.group(1);
}
};
Linkify.addLinks(title, userName, "content://user=", null, transformer);
For some reason however, the whole text becomes one giant link, and the text isn't being transformed at all.
It actually did turned out to be pretty easy. I ended up not using the crazy "$#" to delimit the username, instead sticking with just
User Name: This is a comment I am making
so I ended up using the following pattern
Pattern userName = Pattern.compile("(.+:)");
Very simple, and the code becomes just
title.setText(titleText);
Linkify.addLinks(title, GlobalUtil.userName, "user://" + userId + "/");
Thank you to nil for the original suggestion. I was indeed matching the whole string instead of just the userName which is the link.
My best guess is the regex you're using is the problem, where you're telling it to basically pick out the entire string if it matches, including everything before and after what you're looking for. So, the TransformFilter is probably being passed the entire matched string. transformUrl as far as I can tell expects you to return the URL, so the entire string is linked to the first match group.
So, with that in mind, it's probably in your best interest to change the regex to something along the lines of "\\$#(.+?)\\$#" (with an added ? in the group to make the match non-greedy) so as to avoid matching the entire string and just picking out the bit you want to URL-ize (for lack of a better term, plus adding -ize to words sounds cool).
Why not put the delimiters inside the pattern to change ?
Pattern userName = Pattern.compile(".*(\\$#.+\\$#).*");
Then change the transform filter to remove the start and end patterns when changing into the URL...

Passing Parameters via URI in Android

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

Categories

Resources