安卓中的bundle有限制吗?

26

我想知道Android Bundle的数据大小是否有上限。我试图通过Bundle发布大小超过80k的数据,结果抛出了Android致命异常。这些数据是可序列化的。


我猜这取决于Android版本,在Android 9或更低版本中,我们在设备上遇到了tooLargeDataException异常,但不会出现在新设备上,因为它们使用的是较高的Android版本。 - pintu236
7个回答

52

这取决于Bundle的目的。Bundle本身仅受内存限制。

Bundle的两个主要用途是通过Intent在组件之间传递信息和保存Activity的状态。

1. Intent / Binder

当用于在Android组件之间传递信息时,Bundle将被序列化为Binder事务。进程中所有Binder事务的总大小为1MB。如果超过此限制,将收到致命错误“!!! FAILED BINDER TRANSACTION !!!”。

建议您将这些Bundle中的数据尽可能保持小,因为它是一个共享缓冲区,任何大于几千字节的数据都应该写入磁盘。

参考:https://android.googlesource.com/platform/frameworks/base/+/jb-release/core/jni/android_util_Binder.cpp

ALOGE("!!! FAILED BINDER TRANSACTION !!!");
        // TransactionTooLargeException is a checked exception, only throw from certain methods.
        // FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION
        //        but it is not the only one.  The Binder driver can return BR_FAILED_REPLY
        //        for other reasons also, such as if the transaction is malformed or
        //        refers to an FD that has been closed.  We should change the driver
        //        to enable us to distinguish these cases in the future.

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

Binder事务缓冲区有一个固定的有限大小,目前为1MB,该大小由进程中所有正在进行的事务共享。因此,即使大多数单个事务的大小都是适度的,当有许多事务正在进行时,仍可能抛出此异常。

2. 保存实例状态(Activity onSaveInstanceState,onPause等)

我发现在用于保持Activity状态的bundle中,我可以存储无限制的大小。我进行了一些测试,并成功地存储了约175MB的数据,然后尝试分配要保存的数据时遇到了内存不足异常。

更新:这项研究是在2014年进行的,Android的新版本可能会崩溃,如果Bundle超过500KB。


1
我对您在“保存实例状态”上进行的测试很感兴趣。当我在onSaveInstanceState()中将一个巨大的字符串放入bundle时,Logcat中出现“FAILED BINDER TRANSACTION”错误。看起来数据已经被正确保存和恢复。唯一的问题是日志中出现了上述错误,如果在某些设备/ API版本上失败,这会让我烦恼。当您成功存储了175mb时,是否也遇到了此错误? - yongsunCN
3
在 Android 7.0 及以上版本中,2 不成立。请参见 https://developer.android.com/about/versions/nougat/android-7.0-changes.html 的底部。 - Reuben Tanner
3
@yongsunCN:175MB的说法是错误的。在Android 7.0以上版本(Nougat),当Bundle的大小超过限制时,会抛出异常,而这个限制远远不到175MB,大约只有0.5MB左右。之前的版本仅记录警告,但从该版本开始会抛出异常。 - Minas Mina

13

我认为限制是 500kb。 您可以将传递的对象保存在文件中,然后将文件路径保存在捆绑包中。 您可以查看我的类似问题,网址为SO


1
你有那个数字的参考资料吗? - Nanne
请查看此处的讨论 - Tarun
1
在那个讨论中,你会看到几个数字(500kb和1mb),其中后者是由一位自称为“Dianne Hackborn Android框架工程师”的人提供的,所以如果你想从那个帖子中得到一个数字,我会选择那个。此外,我不太确定那里的主题是“bundle data”。 - Nanne
我认为Hackbod的评论是与Binder RPC有关,而不是Bundle。 - Tom
限制在某个设备上是介于略小于512KB和略小于1MB之间。有关更多信息,请参见此博客文章http://nemanjakovacevic.net/blog/english/2015/03/24/yet-another-post-on-serializable-vs-parcelable/。 - Nemanja Kovacevic
1
Bundle本身既不能限制其持有的数据,也不知道它持有多少数据。Binder事务限制数据大小。 - Miha_x64

4
Binder交易缓冲区有一个有限的固定大小,目前为1MB,由进程中所有正在进行的事务共享。由于这个限制是在进程级别而不是每个活动级别上,因此这些事务包括应用程序中所有绑定器事务,如onSaveInstanceState,startActivity和与系统的任何交互。当超过大小限制时,将抛出TransactionTooLargeException异常。

对于savedInstanceState的特定情况,数据量应该保持小,因为系统进程需要保存所提供的数据,以使用户可以随时返回到该活动(即使活动的进程已被杀死)。我们建议您将保存的状态保留在50k以下的数据。

Parcelable and Bundles

1

是的,它已经有了,并且现在在Android Nougat中,如果您超过了大约500Kb的限制,它将会崩溃。

Android Nougat问题


0

我认为最大的捆绑大小是1024千字节。为了在活动之间传输大对象,您应该尝试其他方法(内存缓存、本地存储等)。


1
1024是什么?你有参考资料吗? - Nanne
1024字节。我记得在某个地方读过这个,也尝试在代码中使用更多的字节,但导致了致命错误。如果我找到更具体的信息,我会告诉你。 - Dimitris Makris
当您接收数据时(n4 4.2.2),您不会遇到致命错误,数据似乎是随机的。 - Edison
3
这是错误的,1024字节太少了 :) 实际限制应该是1MB,但大多数情况下都会更少,详细信息请参见此帖子 http://nemanjakovacevic.net/blog/english/2015/03/24/yet-another-post-on-serializable-vs-parcelable/这句话的意思是:1024字节太少了,实际上的限制应该是1MB,但通常情况下更少。请查看该文章获取更多详细信息。 - Nemanja Kovacevic

0

我们建议您将保存的状态保持在少于50k的数据范围内。这不是一个限制,而是一个建议。 - Miha_x64

-1

是的,它有1MB的限制。

您可以使用Singleton类传递数据。


4
单例类不会在应用程序重新启动时保留。Android操作系统可能会重新启动您的应用程序并尝试使用保存的实例和意图包继续运行。这将导致返回后台停留过久的应用程序时出现空指针异常。 http://www.developerphil.com/dont-store-data-in-the-application-object/ - fthdgn
单例类仅用于在活动或片段之间传递数据。 - Dayanand Waghmare
使用正确实现的单例类,可以放心使用@fthdgn。 - tauitdnmd

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