I'm implementing an option for sharing content from my app. When the user presses the share button the following code is executed.
public static void openShareIntent(Context context, String text, Wish wish)
{
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("text/plain");
share.putExtra(Intent.EXTRA_TEXT, text);
share.putExtra("share_wish", wish);
startIntent(context, share);
}
I'm setting one special extra for my Intent, that is object wish witch implements the Parcelable interface.
This object contains some extra information. I want to use this information if the user selects my app (current app actually sharing content) from the available apps for sharing text/plain.
But the problem is that all other popular apps (Facebook, Twitter, ...) and built-in apps (Messaging) crash when I include my Parcable object. It's not my applications that crashes, other apps are throwing quit unexpectedly error.
When I call my SharingActivity with some extra name that is not known to this Activity, it does not crash. It just ignore that extra.
Wish object source code
Am I doing something wrong or what?
Is this not possible because other apps don't know my Wish object?
But the problem is that all other popular apps (Facebook, Twitter, ...) and built-in apps (Messaging) crash when I include my Parcable object.
Never pass a custom Parcelable object to an app that lacks your Parcelable class definition.
Is this not possible because other apps don't know my Wish object?
Correct.
Instead, pass an identifier (string, int, whatever) that SharingActivity can use to find your Wish from your central data model.
Or, instead of creating a custom Wish, use a Bundle to represent the "wish", as Bundle has a common class definition across all apps.
You could just put your data in a bundle and send it with intent as well.
eg:
Bundle b = new Bundle();
b.putParcelable("object_key", yourObject);
shareIntent.putExtra("bundle_key", b);
Related
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.
So, I've been checking a couple of posts related to opening apps from the browser but my question is.
If I want to open the app but I also want to send a string in the link (the string will containt some passcode to open a certain part of the app that needs to load some specific information depending on the string I send)
How to achieve this? So far I can open the app and also have a fallback url if the app is not installed. Where can I put the parameter I'm trying to send?
In the example it opens the app, but how can I send say, a variable code="112233code"?
Take a QR code
Thanks!
Here's a question that might help you!
I don't know how you open your app from the browser, but if you are using an intent like this:
Do Whatever
Then you can enconde your parameter like this:
Do Whatever
This will pass an extra String called "mycode" with the value "112233code".
In your Android app, you can recover those extras in the onCreate method in the following way:
Bundle extras= getIntent().getExtras();
if (extras != null){
String mycode= extras.getString("mycode");
}
I would like to use a ShareActionProvider to share the contents of my ListFragment (which consists of text entries from an ArrayAdapter fed with a ArrayList<MyObject>).
How do I do this?
I know that I will have to create a new Intent and to use setType("text/plain") but for setAction() should I use Intent.ACTION_SEND and Intent.ACTION_SEND_MULTIPLE?
When setting the content, should I use putExtra or putParcelableArrayListExtra?
Do I set the Intent with the data from the ListFragment, or from the ArrayAdapter, or from the ArrayList<MyObject> that is fed into ArrayAdapter, or from the data before the ArrayList were constructed?
for setAction() should I use Intent.ACTION_SEND and Intent.ACTION_SEND_MULTIPLE?
That is your choice to make, as the author of the app. If you are expecting to share one piece of text (that you assembled from many pieces yourself), use ACTION_SEND. If you are expecting to share many pieces of text, use ACTION_SEND_MULTIPLE.
Note that I would expect about a 100:1 ratio of apps supporting ACTION_SEND compared to ACTION_SEND_MULTIPLE. So, if your objective is for this sharing to be generally useful, you would want to steer towards ACTION_SEND.
More importantly, you need to determine what the users are going to want to do. Presumably, the point behind your development is for 1+ humans to use this app. If the user of the app is expecting to send one email, or post one tweet, or upload one note based on this data, you should be using ACTION_SEND. If, instead, the user will be expecting to send N messages (or whatever), then that would be something to try with ACTION_SEND_MULTIPLE.
When setting the content, should I use putExtra or putParcelableArrayListExtra?
For ACTION_SEND, it would be putExtra(), passing in the String. For ACTION_SEND_MULTIPLE, it would be putStringArrayListExtra().
Do I set the Intent with the data from the ListFragment, or from the ArrayAdapter, or from the ArrayList that is fed into ArrayAdapter, or from the data before the ArrayList were constructed?
You use a String or ArrayList<String> as noted above. Where you get those values from is your business logic that you as a developer need to decide.
My code is as follows:
First, I was wondering about line 20:
I had two questions:
a. Why is MY_MESSAGE assigned to com.example.myfirstapp.MESSAGE?
b. What is com.example.myfirstapp.MESSAGE?
c. I mever made MESSAGE anywhere; is this automatically made like the variables in r.java file, or do i need to make it somewhere?
Secondly, about line 40: intent.putExtra(EXTRA_MESSAGE, message);
I am not sure if this method adds a message to the upcoming activity to be called or what... Partly, I am struggling to understand this due to not knowing the point of an Intent fully.
I want to read my 200 fundamental section on what everything is, but I have set deadlines and I have been told not to take that approach for the time being for this project
With given the explanation of the Android Docs , I know an intent is:
The Intent itself, an Intent object, is a passive data structure holding an abstract description of an operation to be performed
A.) Could someone explain what the intent is used for or give some better quick articles than just the docs?
B.) Explain what putExtra( ) does and and these parameters more clearly:
name The name of the extra data, with package prefix.
value The String array data value
An Intent is appropriately named; it's what you want to be done. As the documentation says:
Its most significant use is in the launching of activities, where it can be thought of as the glue between activities. It is basically a passive data structure holding an abstract description of an action to be performed.
By your code, you are familiar with starting an Activity via Intent:
new Intent(this, DisplayMessageActivity.class);
This uses your current Activity as the context from which to start the Intent, and gives the target class to launch. You already know this, I think. Basically, the Intent is just a guide for the Android device to follow so that it launches the right target with the right information.
Onto your real questions:
"What is the intent used for?" This is described above; basically, it's used to tell the OS what your target is, where it's coming from, and what data it should provide. You've seen most of this in action without realizing; this constructor is the one you've been using, detailing the "from" and "to" portions. When you use putExtra, you are providing the Intent with data it can give to the "to" part of the code.
The name parameter is best summed up by the documentation: "The name of the extra data, with package prefix." This is like a key in a HashMap; it is a string identifier of the content you are packaging. They tell you to use your package's prefix, just to prevent confusion. In your case, you should be using "com.SG.Three_Piece_Radio.YOURKEYNAME"; this does not have to be declared anywhere, nor is it a constant. Just a string. The value is just the contents of the extra (the data); this can be a ton of different things--short, int, String, Parcelable, and many more. (These can all be found in the various putExtras in the Intent docs.)
Once your Intent is received, you can use those same bits of data (for example, String myStr = getIntent().getStringExtra("com.SG.Three_Piece_Radio.YOURKEYNAME");) and do whatever you wish with them in the Activity you called.
I think people have been very helpful here in giving great explanations about Intent itself and its purpose. I got to learn a lot from these answers.
However, there was a small aspect that I think needs a little more explanation.
So to answer your very first question that says :-
a. Why is MY_MESSAGE assigned to com.example.myfirstapp.MESSAGE? b. What is com.example.myfirstapp.MESSAGE? c. I mever made MESSAGE anywhere; is this automatically made like the variables in r.java file, or do i need to make it somewhere?
My answer would be :-
So as all explained, putExtra is meant for carrying additional information/data along with the intent for the new activity that is going to be started. This additional information that putExtra carries is given in Intent in the form of a Key-Value pair.
In this Key-Value pair, the Key syntactically always has to be a String.
In your case, the value is also a String and the "key" can be any random string.
Now, to make sure that the system does not confuse your KEY with some other app's KEY you should always append the entire packet structure of the string along with it. And hence you use :-
com.example.myfirstapp.MESSAGE
where MESSAGE is actually the name of the key, (the String as is required, as I mentioned above) that would be associated with the string value that would be passed with the intent to the new activity.
Now you could have very well written the following as well :-
intent.putExtra("com.example.myfirstapp.MESSAGE", message);
instead of :-
intent.putExtra(EXTRA_MESSAGE, message);
but then this would reduce the flexibility of your code for changes to be made later. As for any changes in the key name you will have to change it everywhere. So to avoid this we rather assign the name of our key (in your case, MESSAGE) to a String variable (in your case EXTRA_MESSAGE).
This also makes it easier for other activities to reference this key by a simple String variable. And so to make it accessible to other activities (coupled with other self explained features)you make it as :-
public final static String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";
Please correct me if I happened to miss something or went wrong somewhere.
The most common use of intents is to start new activities (screens)within an application (line 41). The extras Bundle is a way of passing data between activities. Extras are entered as key value pairs so EXTRA_MESSAGE is a key is used to identify a particular value so it can be retrieved and used by another activity.
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).