我无法在两个活动之间传递过大的对象数组列表?

5

我想在两个Activity之间通过intent传递自定义对象的ArrayList,但是我遇到了错误,不知道该如何解决。如果有人能帮助我,我将不胜感激!提前致谢。

第一个Activity中的方法:

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

在第二个活动中的get方法:

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

错误日志:

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) 

这个数组有多大? - Tim Biegeleisen
1
访问此链接可能有助于您理解 http://jyvee.com/passing-large-data-to-an-activity/ - Zeeshan Shabbir
你将哪些数据传递到下一个活动?如果是图像,请使用位图。 - Aditya Vyas-Lakhan
这是你的问题的答案,由“David Wasser”提供[链接](https://dev59.com/s23Xa4cB1Zd3GeqPfHsv#14446235) - Zeeshan Shabbir
这是我正在尝试传递的数据:http://mar.gt4host.com/market/public/webservice/listallmarkets @TimBiegeleisen - Dev HH
@Lakhan 这里是数据 http://mar.gt4host.com/market/public/webservice/listallmarkets - Dev HH
5个回答

7
所有提供的答案都似乎质量不高,所以我将提供另一种解决方案。
问题:
您遇到的异常是由于您尝试通过Bundle传输的数据量过大导致的。
注意:我在我的网站上写了一篇关于这个主题的博客文章,其中包含更详细的信息。您可以在这里找到它:http://neotechsoftware.com/blog/android-intent-size-limit 解决方案:
您无法通过标准方式(使用Bundle或Parcel)传输对象,因为它太大了。在这些情况下通常使用以下两种解决方案:
基于文件的临时存储和传输
基于内存的存储和传输
基于文件的解决方案:
你可以将自定义对象的数组存储在文件中,稍后再读取。我不建议这样做,因为它通常比内存存储慢。然而,经常使用的技术是使用适当的数据库。然而,使用数据库有一个主要缺点,存储在数据库中的对象通常是临时对象,因此您需要在完成读取后将它们删除。如果出现问题,您的数据库可能会开始包含杂物。因此,您需要某种清理程序。避免这种情况的最佳方法可能是将数据库文件(或实际上用于此目的的任何文件)写入缓存目录。
内存1:(应用程序实例)
您最好的选择(也可能是首选的Android方式)是将数组存储在“Application”实例中。要执行此操作,您需要创建一个类并使其扩展“Application”。在此类中,创建一个公共字段以写入和读取数组。
public class App extends Application {

    public ArrayList<YourObject> objects;

}

你可以通过获取Application实例来读取和写入此字段。
App app = (App) getApplicationContext();
app.objects = yourArrayList;

不要忘记在manifest.xml文件中注册您的扩展Application类!为什么会生效:这是因为Application实例不会在不同的活动之间被销毁,它具有与UI无关的生命周期。
内存中的另一个选项是使用单例模式或创建具有静态字段的类。下面的示例演示了单例模式。
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;

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


你好,我有一个疑问。目前,我需要加载一些文件并将它们存储在ArrayList中。因此,在我的SplashScreen中,我启动了一个JobIntentService来执行加载操作,然后在加载完成后,将ArrayList存储到我的Application类中的静态ArrayList中。现在假设Android OS决定杀死我的应用程序/活动,那么Application中的ArrayList也会被清除吗?如果是,那么您的解决方案是否也会出现相同的行为?我计划使用的解决方案是否具有与您的解决方案相同的效果?请帮忙。 - Rahulrr2602

0

当使用意图附加项传递大量数据时,这种情况经常会发生。

您的选项:

  1. 定义一个公共变量,可以使用变量从另一个类访问:

您将拥有数组,但我的示例具有整数:

enter image description here

现在,您想从另一个类访问这些整数,对吗?目前,您正在通过意图额外发送int到其他活动。相反,您可以创建MyClass的对象并以此方式访问它们:

enter image description here

  • 创建一个带有数组数据的共享首选项对象,并从其他类访问数据。

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

  • 要进行编辑:

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

    2
    不清楚 MyClass 本身将存储在哪里。将 1 MB 的数据写入共享首选项,即仅为 XML 文件的方式也存在问题。 - Alexander Kulyakhtin
    @AlexanderKulyakhtin 实际上,MyClass 是带有您的数组的类。现在,在您的另一个类中,创建一个 MyClass 对象并访问成员变量。如果可以,请告诉我它是否有效! - Ruchir Baronia
    @AlexanderKulyakhtin 很好!你选择了哪种方法? - Ruchir Baronia
    @RuchirBaronia 第一个,我将其设为公共的。 - Dev HH
    @Rolfツ 哦,没错。你是指整数吗? - Ruchir Baronia
    显示剩余2条评论

    0

    -2

    使用意图(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
        } 
    }
    

    你可以在一个Activity中加载数据,然后当你跳转到另一个Activity时,你可以简单地使用:

    ArrayList<> data = MyData.get().getData();
    

    -2

    你不能这样做,否则会导致你的应用程序冻结。将数据存储在Application派生对象中,以便在需要时始终存在。


    1
    这实际上是一个比被接受的答案更好的答案,尽管提供的信息量可以更好。 - Rolf ツ
    无内容。只需添加更多细节 ;) - Rolf ツ
    请纠正我,static对象不是在整个应用程序的生命周期内存储在RAM中吗?这意味着您将永久占用12Mb的设备RAM,这听起来不是一个好主意考虑到上限大小。我可能会考虑在需要时惰性初始化这些对象,而不是将它们全部存储在static ArrayList中。 - PPartisan
    为什么在你不再需要数据时要将变量设置为null?这样数据就不会被引用,因此可以被垃圾回收。 - Alexander Kulyakhtin

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接