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

时间:2015-12-25 07:16:01

标签: java android android-intent arraylist

我正在尝试在两个活动之间传递自定义对象的数组列表抛出意图但我得到了这个错误,我不知道如何解决它。如果有人能帮助我,我将不胜感激!提前谢谢。

传递第1个活动的方法:

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

进入第2个活动的方法:

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) 

5 个答案:

答案 0 :(得分:4)

提供的所有答案看起来质量都不高。所以我会提供另一个。

问题

您获得的例外情况是由于您尝试通过捆绑包传输的数据量太大而造成的。

  

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

不要忘记在Application文件中注册您的扩展manifest.xml课程! 为什么这样做:这是有效的,因为Application实例不会在不同的活动之间被销毁,它的生命周期与UI无关。

内存2(单身)

另一种选择是使用单例模式或创建具有静态字段的类。下面的示例演示了单例模式。

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并传递一个非空的&#34;已保存的实例状态&#34; Bundle方法的onCreate()。您可以假设此时(因为Bundle非空)您的内存存储对象存在,但这不是真的! 结论:始终检查存储的对象是否为非空!

答案 1 :(得分:0)

参考:http://developer.android.com/reference/android/os/TransactionTooLargeException.html

  

Binder事务缓冲区的固定大小有限,目前为1Mb,   由进程中的所有正在进行的事务共享。   因此,当存在许多异常时,可以抛出此异常   即使在大多数个别交易中,交易仍在进行中   中等大小。

答案 2 :(得分:-1)

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

您的选择:

  1. 定义一个可以使用变量从另一个类访问的公共变量:
  2. 您将拥有数组,但我的示例有内联:

    enter image description here

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

    enter image description here

    1. 使用数组数据创建共享首选项对象,并从其他类访问数据。

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

    2. 编辑:

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

答案 3 :(得分:-2)

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

答案 4 :(得分:-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
    } 
}

您可以在一个活动中加载数据,然后当您跳转到另一个活动时,您只需使用:

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