Intent.putExtras size limit? - java

I'm trying to pass data from one activity to another via Intent.putExtras like this:
private ArrayList<HashMap<String, String>> mGroups = new ArrayList<HashMap<String, String>>();
private ArrayList<HashMap<String, String>> mUsers = new ArrayList<HashMap<String, String>>();
...
Bundle data = new Bundle();
data.putInt("mode", mode);
data.putSerializable("groups", (Serializable) mGroups);
data.putSerializable("users", (Serializable) mUsers);
data.putInt("current_class", mCurrentClassId);
data.putInt("current_user", mCurrentUserId);
Intent intent = new Intent(ctx, ChildActivity.class);
intent.putExtras(data);
ctx.startActivityForResult(intent, 0);
Here mUsers is a List of HashMap<String,String> with users' data, including Base64-encoded photo, sum of strings sizes in this list is about 500Kb
Call to startActivityForResult hangs for several minutes with black screen and then I get ANR error. Sub-Activity's onCreate is not called at all.
If I don't add large strings into mUsers (no Base64-encoded photos) - works just fine.
Please help.

if both activities are yours, use a decent data model. Android doesn't encourage that much to very well designed application. Or turn it differently, it allows for fast developped application and doesn't promote much of good software application principle.
The solution of #Jean-Philippe Roy (québec ?) is interesting but singleton are quite an anti-pattern when it comes to more elaborate things, namely statefull models or serviceS.
The best option is to use an application class. This class is your singleton, by nature in android. So,
define an application class in your manifest
provide a static method to access the unique instance of the application class (it is always a singleton).
give it a method to receive and hold your data, call it from your first activity
and a second one to get them back in your second activity
---Updated after #straya's answer and 18 more month of Android programming :)
The question of sharing a data structure or processes accross application, activities, views, fragments is always present at mind when building Android application. It's important to know and consider that the application scope is the right place to hold shared structure, but using the application class itself to put a data structure in that scope is not viable with regards to :
code quality, if all shared data structures and process are know of the application, it will quickly become bloated with accessors for all those entities.
there is only one global shared pool of entities, which is not find grained enough and may lead to hard to detect ways of coupling entities
I now tend to prefer using Dependency Injection managed singletons. Dagger or RoboGuice both allow to create and inject a single instance of a given class into other classes. This technique, and DI more generally offers great possibilities for good Android designs :
don't degrade quality of code, it is even shortened quite a lot. Use #Inject to inject dependencies and they will get injected.
don't give 2 responsibilities to the singletoned class : it will not handle the singleton instance creation, the framework will do it.
it's easier to pass from a singleton to a normal instance
as those singletons become normal classes with a simple annotation, they do not contain static methods anymore and this allows to mock them very easily. And that's a big point.
and of course, DI annotations make it very clear when a class depends on another class, helping to self document code more.

Maximum size is 1MB at Process Level, not at bundle level. This 1MB is for a shared buffer used by all state transactions in progress in the app's process, e.g. onSaveInstanceState, startActivity and others.
On Android 7.0 (API level 24) and higher, the system throws a TransactionTooLargeException when this process level limit is reached. On older versions you only get a warning.
As others suggested, you should research alternatives, if you need to pass a larger payload, e.g. use local database, file system, application level in-memory cache, remote storage, shared preferences (although these need to be small too), etc.
Source of truth: https://developer.android.com/guide/components/activities/parcelables-and-bundles

Just in response to Snicolas' answer:
Application is already a Singleton, no need to "turn it to" one.
Personally, after some serious reliance on Application to hold data for a long time, I've come to not trust it entirely. I use self-caching data objects to mitigate the problems though ;)

Related

manage global object or list

I have read many blogs about how singleton are vulnerable in android.so my question is how to maintain such global objects or list in application.i know shared preference is one way but is there any way to maintain such objects or list efficiently.any help will be more helpful.
You can use a file or SQLite database to save data in android app. You can check below links to learn more about saving data in a file or SQLite database:
Saving data to a file is ideal to store long sequences of data that are generally read in order
https://developer.android.com/training/basics/data-storage/files.html
Saving data to a database is ideal for repeating or structured data:
https://developer.android.com/training/basics/data-storage/databases.html
use sharedPreferences, Sqlite database to manage your objects, singletons are not very good, but static variables are more hard to maintain and will make testing the cide more tough, you can use Shared preferences to maintain a global state if the data is not very large, if there is large amount of data then use of sqlite is recommended.
Shared preferences are extremely easy to use, if you have problem using sqlite though you can use orm libraries for android
here's a link to one: http://greenrobot.org/greendao/
If you just want to keep a list as Global until your app is running, then create a new class let's say "Helper" and Initialize a Static List in that class. Now you can access that list anywhere within the app by "Helper.yourStaticListName" and you can also add/remove or get data from the list anywhere within the app.
But if you want to keep that list even when app has been closed, then there are two solutions for that.
First Create a local database "SQLite file" in your app and add/remove or get data from it.
Check this tutorial: http://www.androidhive.info/2011/11/android-sqlite-database-tutorial/
Second solution is to convert your data into a JSON and convert that JSON into String and save it in Shared Preferences. And whenever you need it just get the string from Shared Preferences and convert it into JSON and parse to get the data.
One last thing when you are talking about parsing a JSON, then "GSON library" is a good thing to work with.
Here is the link: http://guides.codepath.com/android/leveraging-the-gson-library
Hope this answer will help you.
How about using Android Service?
You can initialize / start it when your application started (and also stop them when your application stopped) and then bind them whenever you need (put and get your object / list).
I believe it will be an efficient way.
From conceptual point having a static variables or service-locators is very similar to having Singletons. Hence, having them as alternatives may not be be correct, if the intention is to avoid the Global state and consequences.
We can change Singleton-classes into instances, which are instantiated only once and injected into the components and methods as needed. We can use a IoC-framework to handle the injection part or do it manually with a factory pattern to construct (we can restrict only one instance creation as well) instances of the classes. This discussion thread gives lot of insights on the problem and various options.
So if I understand your question right, you need to store some global variables all over your application if that's so please take a look at this question
basically you create a class that extends application which would store anything you would like on start of your app and all of them can be accessed trough out the app.
hope this helps.
If you are trying to create a globally accessible object, the first thing you should ask yourself is: Why? Why do you need a globally accessible object? Most of the time you don't, and you can get away with creating an object with a limited scope which is passed around the app.
There are times when you do want globally accessible resources and using a singleton is just one way to accomplish that. According to the Android Docs your data storage options are:
Shared Preferences
Store private primitive data in key-value pairs.
Internal Storage
Store private data on the device memory.
External Storage
Store public data on the shared external storage.
SQLite Databases
Store structured data in a private database.
Network Connection
Store data on the web with your own network server.
Singletons are great, but the do have their own risks based on how they are implemented. Typically developers use this pattern when you are attempting to share a resource within the application, things like Loggers, Print spoolers, etc. There are multiple ways that you can create Singletons in Java, you can use a Lazy Initialization or Static initialization, each has their own pro/cons. In terms of "vulnerabilities", there are issues with whether or not the singleton is thread-safe, who/what can access it, and so on. This is why it makes sense to try and understand the problem you are trying to solve. Personally, I'm not clear on what exactly you are trying to solve, so I can't really elaborate on how this might help or hurt you. All I can say is that the biggest vulnerability is also it's greatest asset, which is that like most global variables, it can be accessed from anywhere at anytime. There can also be an issue whether or not the singleton is thread-safe.
Personally, I think you need to assess what it is you are trying to solve and the pick the appropriate solution. Maybe using a singleton is the correct solution, maybe it isn't. But understanding all your options and the strength/weakness of each one is going to be the best way to solve this issue. Unfortunately, you haven't provided enough context to your problem for me, or anyone for that matter, to give you a solid recommendation.
The best way to manage global objects is not having them at all. Based on my experience, in a lot of cases there are alternative options instead using singletons. There is so good explained in this post
shared preference is good but some time you will feel problem when do some modification make static constant variable in one pojo java class and use this variable anywhere.because shared preference will not change value after use or unless you dint modify .shared preference retrieving and storing is not very unfriendly. if you use constant you can modify easily .only one class you have to hit

singleton class that survives Process termination

I've read several post regarding singleton class destruction or singleton pattern is bad in android like this and this
But I am not able to understand how to declare a singleton class properly or use sharedpreference for persistance can anyone provide any example on how to maintain global objects across application or how to achieve this in proper way any help is appreciated.
I think this link you mentioned is quite good.As my personal experience the best way to maintain global objects in an application is to use a class that extends from Application class, then you can manage objects by setter and getter methods in that class.This technically works like a Singleton in android except most of house keeping is done by android so it's very wise to use this mechanism instead of singleton.
On the other hand shared preferences has entirely different job and used for mainly storing some user data and behavior
To save data between process termination you have to use serialization in any form.
The easiest way is to use sharedpreferences + gson.
Singleton would not help because all data with the process will be wiped, OS have a handler to save state in "low memory" situations but it still uses serialization (bundles).
You may use singleton with sharedpreferences, data clients (activities) have to notify about destruction, so singleton can dump data. At start singleton will load data again.
But be aware of possible inconstancy - what if an app will crash?
Things get trickier with multiple processes in one application.

A basic way to have cache/data handled by manager class that my Android Activities can all access?

So what I'm wanting to do is have a few different single manager classes that handle the caching of data that I've pulled down from the internet. I want the data in these classes/objects to be accessible from different activities in my application, whereby any of the activities can manipulate data or call functions as needed.
Eg, I have a UserDatabasemanager where I will store the initial raw JSON data I pull down from the internet and an array of User objects which is a distilled version of that JSON data.
My app at various times will pull data down from the web and will update the User array as data changes. Eg, initially pull down a list of users that fit a criteria. So I then cache all the usernames and IDs into the User objects. Should the application then focus in on a particular user page, it will then download that user's description text and store the new description into User object. (All of which I think I cant do currently with my knowledge of programming)
I've been reading up on sending objects via Intents with Parcelable and Serializable which seems a bit of a round about way of doing things for shared data between Activities.
How to send an object from one Android Activity to another using Intents?
Passing data through intent using Serializable
Since my intention is to use these classes/managers/objects (whatever we want to call them) as single instances I'm not too fussed about following encapsulation to the letter as their job is to provide and update my cache data based on the needs of the Activities.
I'm still very green with all this Android/Java stuff, but it seems this sort of thing would be fairly straight forward in C/C++ with pointers. It seems that even if I was programming directly with Java I could pass around references to objects fairly easily, but the structure of Activities seem to be in such a way that it doesn't lend itself to easy passing data around in my own program?
One easy (but not great) way to achieve this is to use the Android Application class to store (the singleton) instances of your managers. You can always retrieve a reference to your application by calling getApplication() on any activity.
You need to provide your own implementation of the Application class so that you create the managers in the onCreate() method. You should also create strongly typed getters for your managers.
Also, consider what you need to do for the system callbacks the Application may receive such as onLowMemory().
So what I ended up doing in the end is making a Globals.java file with the following contents
public class Globals {
public static ArrayList<User> userObjArray = new ArrayList<User>();
//Weird magic class stuff
private static Globals instance;
private Globals() {
}
public static synchronized Globals getInstance() {
if (instance == null) {
instance = new Globals();
}
return instance;
}
Then whenever I wanted to use data from the Globals I would do something like...
Globals.getInstance().userObjArray
This seems to be working exactly how I want it to. Its not great for encapsulation, but that wasn't the goal for what I needed to get done.
I think you should use android service and create binders in your activities.
http://developer.android.com/guide/components/services.html

Creating globally available map

I am working on an hospital application where i need to show blood group in every second page in drop down and getting values from them to the db tables
since blood group are not frequent changing entity so we are planning to create a map with key value pair and make available this map throughout application in order to avid creation of same map multiple time
my question is what can be the best way to achieve this.some of the quick options coming to my mind are
Create a map at application start up and place it in application context
Create a utility class which read a property file and fill map with these values or simply create map with exisitng blood type.
but i am not sure how effective these options are as site will have to handle a good amount to user hits in near future.
Thanks in advance
Create a utility class that loads these values on system startup or load values when the class loads. Creating a class this way would give few advantages:
You can test this class and its functionality by writing test cases for this class. (Check if things are loading properly etc)
This makes you less dependent on the context and how the context works. Makes your application less troublesome to move if you, for some reason, need to change application server.
Code becomes more readable (BloodGroupUtils.getAll() compared to Application.getContext().get("bloodGroups"); or something similar.)
On Performance, this may be a bit faster. Not necessarily though ( we would need to check several other system usage/parameters to come to that conclusion.)
Retrieving the values from a static class or the application context will have essentially the same performance. The static class might be trivially faster as you don't have to get the map out of the application context, but I can't imagine it'd be worth worrying about.

Is it possible, and what is the best strategy, to pass objects by reference from one Activity to the next?

I have a simple Android application that uses an instance of a class, let's call it DataManager, to manage access to the domain classes in a Façade-like way. I initially designed it as a singleton which could be retrieved using static methods but I eventually got irritated with the messiness of my implementation and refactored to what I reckoned was a simpler and cleaner idea.
Now the idea is that for each file that is opened, one DataManager is created, which they handles both file I/O and modification of the domain classes (e.g. Book). When starting a new Activity, I pass this one instance as a Serializable extra (I haven't got on to using Parcelable yet, but expect I will when I have the basic concept working), and then I grab the DataManager from the Intent in the onCreate() method of the new Activity.
Yet comparison of the objects indicates that the object sent from one activity is not identical (different references) to the object retrieved from the Bundle in the second Activity. Reading up on Bundle (on StackOverflow, etc.) suggests that Bundles cannot do anything other than pass-by-value.
So what is likely to be the cleanest and safest strategy for passing an object between Activities? As I see it I could
Forget about passing by reference and live with each Activity having its own DataManager object. Pass back the new DataManager every time I close an activity so that the underlying activity can use it. (The simple solution, I think.)
Go back to using a singleton DataManager and use a static method to get it from each Activity. (Not keen on using singletons again.)
Extend Application to create a sort of global reference to DataManager. (Again, not keen on the idea of globals.)
Is that a fair summary? Is there some other healthy strategy I could use?
Another approach would be to create a service. The first activity would start the service and bind to it, when you launch a new intent, unbind the first activity and when second activity starts, bind to the service.
This way you don't have to ever stop the service or worry about passing data between activities.
Java does not have pass by reference so that option is out, I would suggest dependency injection for passing data between the activities. Otherwise definetely the singleton would be the way to go.
The prescribed one is Going by implementing Parcellable interface, thats the way to pass Objects between Activities.. and the 2nd and better choice is to make a Singleton to be sure its single Object.
Create your DataManager as a Singleton that implements Service. Bind the service to your application in the manifest xml (see the link), and you will have a persistent singleton your activities can access without issues.
Passing parcellable arguments can quickly get very messy if you need to get a lot of data. The singleton approach, although usually considered an anti-pattern, works like a charm in cases like these. Just remember to not create multiple singletons that interact with one another.
I would suggest using an Application Subclass. It allows you to hold a single reference to the DataManger class and is persistent as long as your app lives.
A singleton with a static field will also work, but there are some place in the documentation where it says that the content of static fields is not a safe place to store your data. As I understand static fields should persist as long as your ClassLoader stays in memory. Therefore a singleton should only vanish if the whole process leaves the memory and in that case the application class will also leave the memory, but it will call the onDestroy methods of the Application and that enables you to safely close your DataManager and persist important data to memory.
That said to your two variations.
The Android way to go would be to make your DataManager a ContentProvider. This will make it possible to access your Data from every Activity without holding a global reference. I'm not sure how you would build a caching Content Provider that stays in memory and is not reinstantiated too often.

Categories