Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I cant pass too large arraylist of objects between 2 activities?

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) 
like image 654
Dev HH Avatar asked Oct 30 '22 12:10

Dev HH


1 Answers

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!

like image 163
Rolf ツ Avatar answered Nov 15 '22 04:11

Rolf ツ