5

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.

Tiger
  • 157
  • 1
  • 3
  • 10
  • Try using a Parcelable. http://stackoverflow.com/questions/2139134/how-to-send-an-object-from-one-android-activity-to-another-using-intents – DunClickMeBro Feb 21 '12 at 20:48
  • Have you tried threading the intent with `java.lang.Runnable`? – John Giotta Feb 21 '12 at 20:49
  • 1
    Perhaps you'd be better served by putting this `ArrayList` in a Singleton, you'll be able to access it from every `Activity` in your application. – Jean-Philippe Roy Feb 21 '12 at 20:50
  • 1
    Does this answer your question? [Maximum length of Intent putExtra method? (Force close)](https://stackoverflow.com/questions/12496700/maximum-length-of-intent-putextra-method-force-close) – Ryan M Jun 05 '20 at 07:52

3 Answers3

7

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.
Snicolas
  • 37,840
  • 15
  • 114
  • 173
  • Thanks, Snicolas, Jean-Phillipe. I've temporarily implemented this as a separate singleton, but will definitely use application class. – Tiger Feb 21 '12 at 22:09
  • 1
    This solution will fail when your application process is restarted and after that you are restoring an activity that tries to read data from in (most commonly, in onCreate method) – Display Name Nov 17 '13 at 19:23
  • @SargeBorsch the `onSaveInstanceState()` can save in that case! – Muhammad Babar Feb 13 '15 at 20:23
  • I do adheres to the point that Application class shouldn't not be used to persist data as this will be really a bad architecture. – Muhammad Babar Feb 13 '15 at 20:25
1

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

Andrey Petrov
  • 2,291
  • 2
  • 15
  • 12
  • I deleted my other responses to what I consider duplicates to the current question: https://stackoverflow.com/questions/12496700/maximum-length-of-intent-putextra-method-force-close/62209045 and https://stackoverflow.com/questions/28729955/max-size-of-string-data-that-can-be-passed-in-intents/28730472#28730472 – Andrey Petrov Jun 05 '20 at 07:07
0

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 ;)

straya
  • 5,002
  • 1
  • 28
  • 35
  • Updated, thanks. I would completely agree with you right now. I think it's still good to consider that the application is the right scope to define a singleton. It may not be so appropriate to use the application class to link them to application scope. I now prefer 2 patterns, one of them as you describe. I will update my solution to talk about it. I invite you to comment on it again if you feel like it. – Snicolas Nov 17 '13 at 21:44
  • Hi straya can you please provide any reasons why not to trust Application class to hold data? – Muhammad Babar Feb 13 '15 at 18:43
  • 1
    @MuhammadBabar because Application can be recreated anytime (theoretically due to low memory) by the OS, and you won't always see Application.onTerminate() nor Application.onLowMemory() calls. http://stackoverflow.com/questions/12672584/android-app-application-singleton-instance-gets-recreated – straya Feb 14 '15 at 03:47