Nougat系统上出现TransactionTooLargeException异常

6

我有一个应用程序,在低于Nougat版本的设备上运行良好。

当我在Nougat设备上启动该应用程序并按下主页按钮时,应用程序崩溃,并在logcat中显示以下错误信息:

!!! FAILED BINDER TRANSACTION !!!  (parcel size = 1819712)
Unhandled exception
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 1819712 bytes
    at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3781)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6119)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
 Caused by: android.os.TransactionTooLargeException: data parcel size 1819712 bytes
    at android.os.BinderProxy.transactNative(Native Method)
    at android.os.BinderProxy.transact(Binder.java:615)
    at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3636)
    at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3773)
    at android.os.Handler.handleCallback(Handler.java:751) 
    at android.os.Handler.dispatchMessage(Handler.java:95) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6119) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 

是否有一个简单的解决方案?这个问题只出现在Nougat上。


3
这意味着你在 onSaveInstanceState() 方法的 Bundle 中写入了过多的数据。 - azizbekian
不,我没有传递位图。问题在于该应用程序为什么在Android 7.0/7.1上无法正常工作,而在较低版本上一切都好。 - Marcin Bortel
嗯,崩溃显示您正在向此包写入1819712字节。这在任何版本的Android上都会失败。由于某种原因,您的数据量已大幅增长。由于我们无法看到您的代码,因此无法真正告诉您它为什么以及如何增长。 - CommonsWare
当我找到它的原因时,我会发布解决方案。我正在寻找为什么它在低版本上运行的原因。 - Marcin Bortel
@nuka_cola 如果您使用的是 Nougat 之前版本,那么这个问题就不会成为问题,因为以前它只是一个静默失败。在 Nougat 中,才将其升级为崩溃。 Nougat 行为变更 中有这样的讨论:“现在,系统将 TransactionTooLargeExceptions 重新抛出为 RuntimeExceptions,而不是静默记录或抑制它们。一个常见的例子是在 Activity.onSaveInstanceState() 中存储过多数据,这会导致 ActivityThread.StopInfo 在您的应用程序针对 Android 7.0 时抛出 RuntimeException。” - Brian Yencho
5个回答

6
我有同样的问题。许多开发者在谷歌论坛上抱怨过这个问题,而他们的答案是“按照预期工作(WAI)”,因为他们不建议在状态中保存太多数据。因此,建议仅向Intent添加非常基本的参数。如果您想在活动或片段之间发送数据,
  • Store the data in a (temporary) file and pass around the file URI. This option is probably your only option if you want to transfer large amounts of data to a completely different app. Store the data in the Application instance;
  • Create a singleton container holding the data you pass around.
  • If you are using FragmentStatePageAdapter, add the following code to avoid it saving state data.

    @Override    
    public Parcelable saveState() {
            Bundle bundle = (Bundle) super.saveState();
            bundle.putParcelableArray("states", null); // Never maintain any states from the base class to avoid TransactionTooLargeException
            return bundle;
    }
    

Reference:

https://issuetracker.google.com/issues/37103380

https://www.neotechsoftware.com/blog/android-intent-size-limit


你为我节省了一些时间。非常感谢。 - thanhnd

1

TransactionTooLargeException类的文档中可以得知:

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

您是否检查了在较低的Android API上传递的数据的大小?

我建议在将数据传输到Android 7.0/7.1和其他版本之前记录此大小。可能在不同的Android版本上,您的数据占用不同数量的内存。


0

我通过将数据保存在文件中解决了这个问题。感谢大家的回答。


0

我也是。对于这个问题没有快速的解决方案。

我的解决方案是将数据暂时存储在数据库或文件中。同时,在活动和片段之间只传输所需的数据。

我认为,对于大多数需要处理大量数据的用例来说,这也是更好的设计模式。


0

如果活动中有几个片段,并且每个片段都在执行onSaveInstance,那么这种情况就会更加频繁发生。如果片段的onCreateView总是重新启动视图(不需要恢复视图状态),那么可以使用rootview.setSaveFromParentEnabled(false);来防止视图的onSaveInstanceState()。这可能会有所帮助。


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