I have a working custom search suggestions class (via http://developer.android.com/guide/topics/search/adding-custom-suggestions.html). It currently returns one type of information - "product names".
I've added some additional activities (screens) to my app so that if a person is on a product page, starting up a search should return results from "product names", but if they are in another activity, I would like the search suggestions to pull "manufacturer names".
I saw Accessing appSearchData bundle from ContentProvider, but the custom search suggestions provider extends ContentProvider which doesn't work with the answer
Bundle b = intent.getBundleExtra(SearchManager.APP_DATA);
This Bundle is available to the search results class, but not the contentprovider.
How best to pass a parameter ("product" or "manufacturer") to a search suggestions content provider?
This doesn't seem like an ideal solution, but I had the same need and I found I could get the job done by adding a public ivar or method to the subclass of ContentProvider that handles the search suggestions. Prior to initiating the search, you can configure your provider as needed. You can access the provider instance from an activity like so:
ContentProviderClient client = getContentResolver().acquireContentProviderClient("my.searchsuggestionprovider");
MyProviderClass provider = (MyProviderClass) client.getLocalContentProvider();
Now you can configure with provider.setParameter("product") or whatever you need. You might need to reset the parameter to a default or something after building your cursor.
Edit: This turned out to be impractical, at least in my case, since the content provider is called with query() every time a character is typed. Instead, I have employed a workaround similar to what is described in set-search-hint-dynamically. By creating an alternate "searchable" XML definition and activity, you can alter the URI that's passed to the content provider in query(), adding a path component to provide the additional parameter or context you need.
I just made a static variable for the parameter on my content provider, and set it from the activity. I been thinking about it, and it's the cleanest workaround I have found!
Related
I have a document on Firestore, from which I read its fields in a fragment. Since it has many fields, I set variables in the Activity that hosts this fragment so that I can pass the data between other fragments. In order to achieve that, I realize that I have to write similar lines of codes over and over again, which got me to thinking if there is a better way.
Two possible solutions that come to my mind:
Structure all these fields in JSON format -> something that wouldn't be suitable in Firestore's document system imo
Put all these fields into a serializable data class which I keep in the activity then pass it around the bundles of fragments -> Seemed to complicated and I would still have to write it.get(foo) as bar for each of the field's of this class' constructor.
Given all these, what is the best approach? Thanks in advance.
You have a several options on how to approach this. There is none that's necessarily better than another. Ultimately, you will pick the one that best suits your needs and preferences.
You can do what you're doing now.
You can go a step further an actually check the types of the values instead of just blindly casting them (which would cause a crash at runtime if they didn't match).
You can provide a Class object to get(String, Class<T>) that can automatically map the fields to properties in a new object of type T, as long as the types also match.
You can call a variety of type-specific versions of get, such as getString()
Ultimately you will have to decide if you are going to trust what you get in the snapshot and allow errors to happen, or trust nothing and check everything. It's up to you.
I'm using content URI's to link content (more like launch a specific activity) in an app and other apps that I've developed but the problem is anytime one application is selected from the android launcher the rest of the URI's keep opening using that singular app
I'm building the uri links using the Linkify class. Below shows the URI's
Pattern inlinkMatcher = Pattern.compile("\\(click[^()]*\\)|\\(you can[^()]*\\)|\\(check here [^()]*\\)");
String inLinkURL = "content://com.n4labs.sexed.providers/hgcontent/";
Pattern inlinkMatcher2 = Pattern.compile("\\(click here to find [^()]*\\)");
Pattern inlinkMatcher3 = Pattern.compile("\\(learn more [^()]*\\)|\\(talk to [^()]*\\)");
boolean yfsinstalled = appInstalledOrNot("com.n4labs.yfs");
String inLinkURL2 = "http://market.android.com/details/?id=com.n4labs.yfs";
if(yfsinstalled)
inLinkURL2 = "content://com.n4labs.yfs.providers/centersearch/";
boolean divainstalled = appInstalledOrNot("com.n4labs.diva");
String inLinkURL3 = "http://market.android.com/details/?id=com.n4labs.diva";
if(divainstalled)
inLinkURL3 = "content://com.n4labs.diva.providers/learn/";
And the calls to Linkify
if(yfsinstalled){
Linkify.addLinks(itemController3.paragraphtext, inlinkMatcher2, inLinkURL2);
}
else
{
Linkify.addLinks(itemController3.paragraphtext, inlinkMatcher2, inLinkURL2, null, mentionFilter);
}
if(divainstalled){
Linkify.addLinks(itemController3.paragraphtext, inlinkMatcher3, inLinkURL3);
}
else
{
Linkify.addLinks(itemController3.paragraphtext, inlinkMatcher3, inLinkURL3, null, mentionFilter);
}
Linkify.addLinks(itemController3.paragraphtext, inlinkMatcher, inLinkURL);
The provider in each app has the appropriate authority and is exported as such
<provider
android:name="com.n4labs.diva.providers.HealthGuideContentProvider"
android:authorities="com.n4labs.diva.providers"
android:exported="true">
</provider>
How can I ensure that each URI opens in the appropriate application automatically, or at least the option is displayed to the user every-time.
I hope I was clear enough.
Anyone?
Thanks.
Each of your ContentProviders is reporting that the MIME type associated with those Uri values is text/plain. This is a very common MIME type, one normally associated with standard text files.
When the user clicks on a link for any of those Uri values, Android will construct an ACTION_VIEW Intent, for a MIME type of text/plain, and attempt to start an activity for that, such as a text editor.
The key now is: what do these ContentProviders actually deliver, as content, for those Uri values? In other words, if I were to call openInputStream() on a ContentResolver, passing in one of those Uri values, what data do I get back in the stream?
There are five main possibilities that I see:
They legitimately return plain text, and you really do want an ordinary text editor to be an option for the user to work with that text. In that case, your setup is fine. Bear in mind that the user might elect to click the "always" option for handling these Uri values and therefore may not necessarily want to be presented with a choice of activities each time. After all, in this scenario, all three of your activities can work with all three of your providers, and regular text editors can also work with these providers.
They legitimately return plain text, but you really do not want anything other than your activities handling those Uri values. In that case, get rid of the ContentProviders, get rid of Linkify, and add your own ClickableSpans to the text to directly start activities of your choosing.
They do not return plain text, but instead return data in some other format, and you are willing for third-party apps to be able to work with that content. In that case, change the MIME type (in the provider and in the associated <intent-filter>) to the correct value, instead of text/plain. This may involve you creating your own custom "vendor" MIME type, if your data does not match any standard data format.
The openInputStream() call would crash, because you have a buggy ContentProvider that is not actually serving data for these Uri values. In that case, fix the ContentProvider, then run through this list of possibilities again. Since you are exporting this provider, you need to actually implement it properly.
The openInputStream() call would crash, or the providers would return something other than plain text, but you are not intending on anybody actually using this content other than yourself. In that case, get rid of the ContentProvider, get rid of Linkify, and add your own ClickableSpans to the text to directly start activities of your choosing.
My guess is that your case is #2 or #5.
When i got some cursor i want to be aware for changes, so i have used the registerContentObserver() on my cursor and when change occur i just notify that change happened.
i looked into the notifyChange method on android developer and i didnt see any way to pass some metadata .
when i said metadata i meant any other object which tell me what change happen like delete/update/insert
You can't specifically add any metadata per se, but you can bend the system to pass this information anyway.
When registering your content observer, set the notifyForDescendants parameter to true. Then in your ContentProvider, generate a different uri to add information.
For example if the uri you normally use is content://com.example.app.provider/item/42, you can use one of the following uris to add information :
content://com.example.app.provider/item/42/inserted
content://com.example.app.provider/item/42/updated
content://com.example.app.provider/item/42/deleted
I am looking at a tutorial and see the author using intent.setClass() to get the to the next Activity and then on the same page he uses intent.setComponent() to get to the next Activity.
So what is the difference and what is the advantage in using any of them?
Other than different parameters.
intent.setcomponent() = Explicitly set the component to do the handling of the intent.
intent.setClass() = Convenience for calling setComponent(ComponentName) with the name returned by a Class object.
another difference is that .setComponent() can find the appropiate class for you.
*From android Developers*
SetComponent Android Dev
You should only set this value when you know you absolutely want a specific class to be used; otherwise it is better to let the system find the appropriate class so that you will respect the installed applications and user preferences.
Looking at content providers, I'm not quite clean on the typical usage of the getType() method. The API doc says about implementing this method that
This allows [applications] to retrieve the MIME
type for a URI when dispatching
intents.
Could anyone describe a typical case where using it would be particularly useful?
For example, you're writing content provider for picture gallery. You should mention in your getType() method that you provide pictures - jpg or png. So, when one will launch image gallery, it will be able to show built-in pictures and pictures provided by your content provider.
In pseudocode the user of contentProvider do something like:
List contentProviders = getProviders();
List resultProviders;
final Type type = Type.JPG;
for (ContentProvider provider : contentProviders) {
if (type == provider.getType()) {
resultProviders.add(provider);
}
}
This is pseudocode, but I hope you will got the idea.
As I understand it, a use case could be the following:
App A contains the content provider. App B uses that content provider to retrieve all the data items from App A. The user then picks one of these (in App B) and after that an activity in App A to show/edit/delete the selected data item should be started. So App B then creates an intent, and to make sure that an activity in App A handles it, you need to set the (mime-)type of the intent to the mime-type of the uri (the show/edit/delete activities in App A has added this mime type to their intent filters).