5

I'm trying to pass array list of custom object between 2 activities throw intent but i got this error and i don't know how to solve it. i 'll appreciate if anyone can help me! Thanks in advance.

Method in pass in 1'st activity:

i.putParcelableArrayListExtra("key", (ArrayList<? extends Parcelable>) result);
startActivity(i);

Method in get in 2'st activity:

Intent i = getIntent();
ArrayList<ItemObjects> list = i.getParcelableArrayListExtra("key");

Error Log:

12-25 09:11:49.546 17742-17742/com.example.baha.myapplication E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.baha.myapplication, PID: 17742
java.lang.RuntimeException: Failure from system
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1514)
    at android.app.Activity.startActivityForResult(Activity.java:3917)
    at android.app.Activity.startActivityForResult(Activity.java:3877)
    at android.app.Activity.startActivity(Activity.java:4200)
    at android.app.Activity.startActivity(Activity.java:4168)
    at com.example.baha.myapplication.splash$GetMarkets.onPostExecute(splash.java:127)
    at com.example.baha.myapplication.splash$GetMarkets.onPostExecute(splash.java:62)
    at android.os.AsyncTask.finish(AsyncTask.java:651)
    at android.os.AsyncTask.-wrap1(AsyncTask.java)
    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5417)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
 Caused by: android.os.TransactionTooLargeException: data parcel size 12404332 bytes
    at android.os.BinderProxy.transactNative(Native Method)
    at android.os.BinderProxy.transact(Binder.java:503)
    at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:2657)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1507)
    at android.app.Activity.startActivityForResult(Activity.java:3917) 
    at android.app.Activity.startActivityForResult(Activity.java:3877) 
    at android.app.Activity.startActivity(Activity.java:4200) 
    at android.app.Activity.startActivity(Activity.java:4168) 
    at com.example.baha.myapplication.splash$GetMarkets.onPostExecute(splash.java:127) 
    at com.example.baha.myapplication.splash$GetMarkets.onPostExecute(splash.java:62) 
    at android.os.AsyncTask.finish(AsyncTask.java:651) 
    at android.os.AsyncTask.-wrap1(AsyncTask.java) 
    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:148) 
    at android.app.ActivityThread.main(ActivityThread.java:5417) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
ThatBlairGuy
  • 2,426
  • 1
  • 19
  • 33
Dev HH
  • 91
  • 1
  • 2
  • 7

5 Answers5

7

All answers provided seem a little low quality. So I will provide another one.

The problem

The exception you're getting is caused by the fact that the amount of data you're trying to transfer through an Bundle is simply too large.

Note: I wrote a blog post about this topic on my website, it contains more detailed information. You can find it here: http://neotechsoftware.com/blog/android-intent-size-limit

Solutions

There is no way you will be able to transfer you're object through the standard way (using a Bundle or Parcel), because it is simply too large. There are two solutions that are often used in these cases:

  • File based temporary storage and transfer
  • in-memory based storage and transfer

File based

You could store the array of custom objects in a file and later read it back. I don't recommend doing this as its in general slower than in-memory storage. However an often used technique is to use a database of some sort if applicable. Using a database however has a major drawback, objects stored in the database are often temporary objects so you need to remove them after you're finished reading them. If something goes wrong your database may start to contain clutter. So you need some sort of clean routine. The best method to avoid this is probably to write the database file (or actually any file used for this) to a cache directory.

In-memory 1: (Application instance)

Your best option (and probably the preferred Android way) is to store the array in the Application instance. To do this you would need to create a class and make it extend Application. In this class you create a public field to write and read the array to.

public class App extends Application {

    public ArrayList<YourObject> objects;

}

You can read and write to this field by obtaining the Application instance.

App app = (App) getApplicationContext();
app.objects = yourArrayList;

Don't forget to register your extended Application class in the manifest.xml file! Why does this work: This works because the Application instance won't be destroyed between the different Activities, it has a life-cycle independent from the UI.

In-memory 2 (singleton)

Another option is to use the singleton pattern or create a class with static fields. The example below demonstrates the singleton pattern.

public class DataContainer {

    private static DataContainer instance = null;

    public static DataContainer getInstance(){
        /**
         * Synchronizing this method is not needed if you only use it in
         * Activity life-cycle methods, like onCreate(). But if you use
         * the singleton outside the UI-thread you must synchronize this
         * method (preferably using the Double-checked locking pattern).
         */
        return instance != null?instance: (instance = new DataContainer());
    }

    public ArrayList<YourObject> objects;

}


DataContainer.getInstance().objects = yourArray;

Very important note on in-memory object storage: Assume that your app is in the background and you stored some object in the Application instance (or in a singleton container) to later restore it. If the Android system decides to kill your app because it needs to free some memory for another app, your objects will be destroyed. Now the important part, if the user returns to your app the Android system re-creates the destroyed Activity and passes a non-null "saved-instance-state" Bundle to the onCreate() method. You might assume at this point (because the Bundle is non-null) your in-memory stored objects exist, this is however not true! Conclusion: Always check if stored objects are non-null!

Rolf ツ
  • 8,611
  • 6
  • 47
  • 72
  • Hi, I have a doubt. Currently, I have to load some files and store them in the ArrayList. So in my SplashScreen, I start a JobIntentService which does the loading and then after the loading is done I store the ArrayList to a static ArrayList present in my Application Class. Now suppose the Android OS decided to kill my app/activity will the ArrayList in Application also be cleared? And if yes will the same behavior be observed with your solution. Is the solution I am planning to use has the same effects as yours? Please Help. – Rahulrr2602 May 23 '19 at 13:31
0

This can happen very often when using intent extras to pass large amounts of data.

Your options:

  1. Define a public variable that can be accessed from the other class using variables:

You would have arrays, but my example has ints:

enter image description here

Now, you want to access these ints from another class right? Right now you are sending the int to the other activity via intent extra. Instead, you can make an object of MyClass and access them that way:

enter image description here

  1. Make a shared preferences object with the array data, and access the data from the other class.

    SharedPreferences prefs = this.getSharedPreferences("com.example.app", Context.MODE_PRIVATE);

And to edit:

prefs.edit().putInt(INT).apply();
Ruchir Baronia
  • 7,406
  • 5
  • 48
  • 83
0

Reference: http://developer.android.com/reference/android/os/TransactionTooLargeException.html

The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process. Consequently this exception can be thrown when there are many transactions in progress even when most of the individual transactions are of moderate size.

msevgi
  • 4,828
  • 2
  • 24
  • 30
-2

You can not, or it'll make your app freeze. Store the data in your Application-derived object so they exist all the time you need.

Alexander Kulyakhtin
  • 47,782
  • 38
  • 107
  • 158
  • 1
    This is actually a better answer than the accepted answer, although the amount of information provided could be better. – Rolf ツ Dec 25 '15 at 08:16
  • Nothing. Just add some more details ;) – Rolf ツ Dec 25 '15 at 09:32
  • Correct me if I'm wrong, but aren't `static` objects stored in RAM for the entire life cycle of the Application? This means you would be permanently occupying 12Mb of device RAM, which doesn't sound like a great idea [considering the cap size](http://stackoverflow.com/questions/18675557/what-is-the-maximum-amount-of-ram-an-app-can-use). I would probably look into lazy-initialising these objects as and when they're required rather than storing them all in a `static` `ArrayList`. – PPartisan Dec 26 '15 at 13:22
  • Why, when you don't need that data you set the variable to null and the data will be no longer referenced and therefore will be garbage collected – Alexander Kulyakhtin Dec 26 '15 at 21:15
-2

You can not pass too large object using intent. If you want to using such data in more than one activity, you can define a helper class like the following:

public class MyData {
    private static MyData sInstance = new MyData();
    public static MyData get() { return sIntance; }

    private ArrayList<> data;
    public List<> getData() { return data; }
    public void loadData() { 
        // load data
    } 
}

you can load data in one activity, Then when you jump to another activity, you can simply use:

ArrayList<> data = MyData.get().getData();
Eric Huang
  • 33
  • 4