6

I've go an app that works well on devices with Android versions lower than Nougat.

When I launch the app on a device with Nougat and I press home button, the app crashes and in logcat I have:

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

Is there a simple solution? This problem appears only on Nougat.

Steve Blackwell
  • 5,904
  • 32
  • 49
Marcin Bortel
  • 1,190
  • 2
  • 14
  • 28
  • 3
    That means you are writing too much data in `onSaveInstanceState()`'s `Bundle`. – azizbekian Apr 18 '17 at 07:58
  • No, i'm not passing Bitmaps. Case is why app doesn't work correctly on android 7.0/7.1 but on lower versions everything is ok. – Marcin Bortel Apr 18 '17 at 08:11
  • Well, the crash shows that you are writing `1819712` bytes to this parcel. That would fail on any version of Android. For whatever reason, your data volume has grown substantially. Since we cannot see your code, we cannot really tell you how or why it has grown as it has. – CommonsWare Apr 18 '17 at 13:15
  • I'm looking for a reason why it works on lower versions. i'll post solution when i'll find it. – Marcin Bortel Apr 18 '17 at 14:11
  • @nuka_cola The reason why this isn't a problem on versions earlier than Nougat is that this used to be a silent failure. It was only upgraded to a crash in Nougat. The [Nougat behavior changes](https://developer.android.com/about/versions/nougat/android-7.0-changes.html#other) discuss this : "the system now rethrows TransactionTooLargeExceptions as RuntimeExceptions, instead of silently logging or suppressing them. One common example is storing too much data in Activity.onSaveInstanceState(), which causes ActivityThread.StopInfo to throw a RuntimeException when your app targets Android 7.0." – Brian Yencho Jul 06 '17 at 14:19

5 Answers5

6

I have the same problem. This has been complained by many developers on the google forum. Their answer is WAI (work as intended) because they don't recommend to save too much data in the state. So the advice is to only add very basic arguments to an Intent. If you want to send data among activities or fragments,

  • 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

flame3
  • 2,812
  • 1
  • 24
  • 32
1

From the documentation of the TransactionTooLargeException class

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.

Have you checked the size of data which you are passing on lower android API?

I suggest logging this size before you transferring data on android 7.0/7.1 and others. Possibly on different android versions, your data occupies different amount of memory.

Volodymyr
  • 6,393
  • 4
  • 53
  • 84
0

Same here. No quick solution for this problem.

My solution was to store the data temporary in the database ore the file. Also just trnsmitting only needed data between activitys and fragments.

I think this is also a better design pattern for most usecases with huge data.

0

it happens more if there are a few fragments with the activity and each one is doing the onSaveInstance. If the fragment onCreateView is always to restart the view (no view state needs os to restore), then rootview.setSaveFromParentEnabled(false); to prevent the view's onSaveInstanceState(). This may help.

lannyf
  • 9,865
  • 12
  • 70
  • 152
0

I resolved this problem by saving data in file. Thank you for all your answers.

Marcin Bortel
  • 1,190
  • 2
  • 14
  • 28