我不能在2个活动之间传递太大的对象arraylist?

时间:2021-12-26 16:13:21

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:

传递第1个活动的方法:

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

Method in get in 2'st activity:

进入第2个活动的方法:

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) 

5 个解决方案

#1


-1  

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

当使用intent extras传递大量数据时,这种情况经常发生。

Your options:

你的选择:

  1. Define a public variable that can be accessed from the other class using variables:
  2. 定义一个可以使用变量从另一个类访问的公共变量:

You would have arrays, but my example has ints:

你会有数组,但我的例子有:

我不能在2个活动之间传递太大的对象arraylist?

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:

现在,您想从另一个类访问这些int吗?现在你通过intent extra将int发送到另一个活动。相反,您可以创建MyClass的对象并以这种方式访问​​它们:

我不能在2个活动之间传递太大的对象arraylist?

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

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

And to edit:

并编辑:

prefs.edit().putInt(INT).apply();

#2


4  

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.

您获得的例外是由于您尝试通过Bundle传输的数据量太大而导致的。

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

注意:我在我的网站上写了一篇关于这个主题的博客文章,它包含更多详细信息。你可以在这里找到它: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:

你无法通过标准方式(使用Bundle或Parcel)转移你的对象,因为它太大了。在这些情况下经常使用两种解决方案:

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

内存1 :(应用程序实例)

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.

您最好的选择(可能是首选的Android方式)是将数组存储在Application实例中。为此,您需要创建一个类并使其扩展Application。在这个类中,您创建一个公共字段来写入和读取数组。

public class App extends Application {

    public ArrayList<YourObject> objects;

}

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

您可以通过获取Application实例来读取和写入此字段。

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.

不要忘记在manifest.xml文件中注册扩展的Application类!为什么这样做:这是有效的,因为Application实例不会在不同的Activity之间被销毁,它有一个独立于UI的生命周期。

In-memory 2 (singleton)

内存2(单例)

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!

关于内存中对象存储的非常重要的注意事项:假设您的应用程序位于后台,并且您在Application实例(或单个容器)中存储了一些对象以便以后还原它。如果Android系统决定杀死你的应用,因为它需要为另一个应用释放一些内存,你的对象将被销毁。现在重要的是,如果用户返回到您的应用程序,Android系统会重新创建已销毁的Activity,并将非null“saved-instance-state”Bundle传递给onCreate()方法。您可以假设此时(因为Bundle非空)您的内存存储对象存在,但这不是真的!结论:始终检查存储的对象是否为非null!

#3


0  

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

参考: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.

Binder事务缓冲区具有有限的固定大小,当前为1Mb,由进程正在进行的所有事务共享。因此,即使大多数单个事务的大小适中,当有许多事务正在进行时,也会抛出此异常。

#4


-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.

你不能,或者它会让你的应用程序冻结。将数据存储在Application派生对象中,以便它们始终存在于您需要的位置。

#5


-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:

您不能使用intent传递太大的对象。如果要在多个活动中使用此类数据,可以定义一个如下所示的帮助程序类:

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

#1


-1  

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

当使用intent extras传递大量数据时,这种情况经常发生。

Your options:

你的选择:

  1. Define a public variable that can be accessed from the other class using variables:
  2. 定义一个可以使用变量从另一个类访问的公共变量:

You would have arrays, but my example has ints:

你会有数组,但我的例子有:

我不能在2个活动之间传递太大的对象arraylist?

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:

现在,您想从另一个类访问这些int吗?现在你通过intent extra将int发送到另一个活动。相反,您可以创建MyClass的对象并以这种方式访问​​它们:

我不能在2个活动之间传递太大的对象arraylist?

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

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

And to edit:

并编辑:

prefs.edit().putInt(INT).apply();

#2


4  

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.

您获得的例外是由于您尝试通过Bundle传输的数据量太大而导致的。

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

注意:我在我的网站上写了一篇关于这个主题的博客文章,它包含更多详细信息。你可以在这里找到它: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:

你无法通过标准方式(使用Bundle或Parcel)转移你的对象,因为它太大了。在这些情况下经常使用两种解决方案:

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

内存1 :(应用程序实例)

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.

您最好的选择(可能是首选的Android方式)是将数组存储在Application实例中。为此,您需要创建一个类并使其扩展Application。在这个类中,您创建一个公共字段来写入和读取数组。

public class App extends Application {

    public ArrayList<YourObject> objects;

}

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

您可以通过获取Application实例来读取和写入此字段。

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.

不要忘记在manifest.xml文件中注册扩展的Application类!为什么这样做:这是有效的,因为Application实例不会在不同的Activity之间被销毁,它有一个独立于UI的生命周期。

In-memory 2 (singleton)

内存2(单例)

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!

关于内存中对象存储的非常重要的注意事项:假设您的应用程序位于后台,并且您在Application实例(或单个容器)中存储了一些对象以便以后还原它。如果Android系统决定杀死你的应用,因为它需要为另一个应用释放一些内存,你的对象将被销毁。现在重要的是,如果用户返回到您的应用程序,Android系统会重新创建已销毁的Activity,并将非null“saved-instance-state”Bundle传递给onCreate()方法。您可以假设此时(因为Bundle非空)您的内存存储对象存在,但这不是真的!结论:始终检查存储的对象是否为非null!

#3


0  

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

参考: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.

Binder事务缓冲区具有有限的固定大小,当前为1Mb,由进程正在进行的所有事务共享。因此,即使大多数单个事务的大小适中,当有许多事务正在进行时,也会抛出此异常。

#4


-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.

你不能,或者它会让你的应用程序冻结。将数据存储在Application派生对象中,以便它们始终存在于您需要的位置。

#5


-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:

您不能使用intent传递太大的对象。如果要在多个活动中使用此类数据,可以定义一个如下所示的帮助程序类:

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