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.
Related
Now I am working on Android application which has one main Activity that is displaying some data via GLSurface. This data can be changed in many ways. For this I have several fragments with some lists of variants with extra logic. Problem is that I need somehow transfer data from one place to another.
For example:
I have fragment with list of elements. I used RecyclerView with custom adapter. I am filling list with data from DB. SomeThingDBEntity for example. When I am getting it from Room DB (using Room entities), but it has some extra fields that only required for showing elements in RecyclerView. I need to send user's choice from adapter to fragment, then from fragment to activity, than activity sends it to some class that incapsulates logic of work with GLSurface. SomeThingGLentity for example. Now I am passing only fields, that requered by SomeThingGLentity for showing data (int, String etc.), but in future this list can grow. I can also send directly SomeThingDBEntity and get required fields only in the end when apply changes to SomeThingGLentity. But is it OK to use Room DB entity this way?
Is there any better way of doing this? I can also create third class which will only contain required fields. But where to place and how to call it? Maybe there are some patterns or guidelines of best way of doing it...
It looks like you need a data mapper. Something similar to this - https://github.com/android10/Android-CleanArchitecture/blob/master/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityDataMapper.java.
If you use this approach, you will be able to encapsulate the transformation logic from your DBEntity to your BusinessEntity, and if you will change the data format in one of them, only your mapper will need to be edited.
I intend to pass multiple file-URIs/Paths to my Activity using intent. I have the necessary code in place (i.e. SEND_MULTIPLE in Manifest and getIntent() in Activity) and I am able to get the file-list from the intent in my Activity. However, this file-list is sorted in alphabetical order and not in the same order as I selected my files from Gallery.
Is there a way to get the file-list in same order as I select the files in Gallery?
I am afraid to tell you that it seems like, there are no way to ensure the sorting order of the data send using the Intent. That's why you have to do it by yourself.
I do recommend for you to create a Parcelable object contain two things (int order, String url). Then send the list of the Parcelable objects using the intent. Then implement a simple comparator to sort those object after retrieving them using the order attribute
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);
I'm trying to build a complex form where almost all of the elements are optional. It starts with just a single field and an "add element" button. When you click add, the form shows a Spinner of the types of elements you can add to the form (location, photo, detailed note, timestamp other than "now", etc). When you select an item, it will launch an Activity, and each item has a different associated Activity.
In addition, each choice will have several bits of data, which it would be nice to store "with" the Activity somehow:
An icon and the displayed name in the Spinner
A key for storing the data in the db (as well as passing to a webservice)
A layout for how to display the result on the original form (i.e. a thumbnail for the photo, the lat/lon for the location, etc)
I was considering a set of classes that all extend an abstract FormElement class, and would have static elements for each of the above extra pieces of data. (An additional bump for this solution is how much of a pain Resources are in a static context.)
How can I make this as clean and maintainable as possible? I'd really not enjoy editing five different files to add a new type of element to this form. (Mostly because I can guarantee I'll miss one and spend hours chasing down unbugs.)
A few tips...
Unit tests will prevent "unbugs" :)
When each Activity has obtained the information it needs from the user, call Activity#setResult() with an Intent that contains your per-type data. Intent supports all the Bundle methods, so you can set different types of data as needed.
To support #2, make sure you're using Activity#startActivityForResult(Intent,int) to launch it, and listen for the result in Activity#onActivityResult(int,Intent)
I would probably maintain the list of available "element" types for use with the SpinnerAdapter (e.g., ArrayList<Class<? extends AbstractFormElement>>, and invoke static methods like .getDisplayName(), .getActivityClass(), etc, in the Adapter's getView() method, in order to determine what to display and what Activity to launch.
In this way, your list would actually contain things like { MyPhotoElement.class, MyTextElement.class, MyDateElement.class, ...}).
As each element is added to the form, add it to an ArrayList<AbstractFormElement>, which will be used to back another Adapter for a ListView. That adapter will dispatch the inflation of a custom view layout, as well as the creation of a ViewHolder, based on what type of object it is -- that will require that each distinct AbstractFormElement will have its own "view type", according to the Adapter. See BaseAdapter#getItemViewType(int) and related getViewTypeCount().
It's worth noting that these will need distinct view types only if one cannot be converted to the other... For example, if you have two "Elements" that only need to display a string of text in the list, those can both share a "text-only" view type. Likewise, two elements that only display a photo, or can easily convert one to the other (e.g., an icon with a caption, vs a photo thumbnail with no caption), can share a single "image-plus-caption" view type.
With the above in mind, you actually would end up having to modify different files to add a new type (well, I guess technically you could have them all in one file, as inner classes, but there's really no good argument for doing that), but if you've done your interface API correctly, and follow good OO practices, and implement good unit tests, you'll considerably reduce the amount of effort required to find bugs -- simply because most of the things involved in adding a new type would actually force a compiler error if you do it incorrectly. Add to that the fact that a proper unit test suite will be able to programmatically add all possible types, and ensure that everything displays properly, and you should have a pretty streamlined process for easy extensibility :)
It sounds like a lot of work, and it might seem tedious and verbose at first... But the end result is actually much more maintainable, especially if your list of element types is going to be fairly extensive.
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).