What to do on TransactionTooLargeException
Asked Answered
R

45

329

I got a TransactionTooLargeException. Not reproducible. In the docs it says

The Binder transaction failed because it was too large.

During a remote procedure call, the arguments and the return value of the call are transferred as Parcel objects stored in the Binder transaction buffer. If the arguments or the return value are too large to fit in the transaction buffer, then the call will fail and TransactionTooLargeException will be thrown.

...

There are two possible outcomes when a remote procedure call throws TransactionTooLargeException. Either the client was unable to send its request to the service (most likely if the arguments were too large to fit in the transaction buffer), or the service was unable to send its response back to the client (most likely if the return value was too large to fit in the transaction buffer).

...

So somewhere I'm passing or receiving arguments which exceed some unknown limit. Where?

The stacktrace doesn't show anything useful:

java.lang.RuntimeException: Adding window failed
at android.view.ViewRootImpl.setView(ViewRootImpl.java:548)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:406)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)
at android.view.Window$LocalWindowManager.addView(Window.java:557)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2897)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4977)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
... 16 more
android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:406)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)
at android.view.Window$LocalWindowManager.addView(Window.java:557)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2897)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4977)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)

It seems to be related with views? How is this related to remote procedure call?

Maybe important: Android version: 4.0.3, Device: HTC One X

Recipience answered 12/7, 2012 at 12:1 Comment(8)
No. But I didn't get it again. Have error tracker in the live app and got it only this one time in about 3 weeks. At least it doesn't seem to happen frequently. Maybe worth to open an issue at Android although...Recipience
I don't have an answer but this reliably causes my Galaxy S2 to hard reset.Charbonneau
I have just had this occur in one of my applications today. This has also only happened once and with a Galaxy S3. Its interesting that this only seems to be apprehending with the more powerful devices.Fourteenth
that exception was added in API 15, developer.android.com/reference/android/os/… And I have reproduced it in the MapView while scrolling around the map. until the gc wrote that I have no memory left.(It took me couple of minutes)Paperweight
The transaction buffer is limited to 1MB on all devices, and this buffer olds every transaction. So the more powerful the device the more transactions it may perform simultaneously, all of which consuming the same 1MB buffer. That said, your answer is not an answer but a comment.Hyman
I never encountered this exception before in my app but since kitkat, many reports come everyday with this error, in differents contexts. Does someone know if kitkat changes something about it, my own personnal search on the subject did not lead my anywhere. So maybe the buffer size has changed ?Dilantin
For those of you having this problem under android Nougat, please read this issue: code.google.com/p/android/issues/detail?id=212316 It appears that since Nougat, "the 1Mb Binder transaction buffer is shared by all transactions in progress for the process."Ramires
this is caused because of the bitmap size is large, why not you create URI for that bitmap and pass that URI to intentOvid
B
196

I encountered this issue, and I found that when there huge amount of data getting exchanged between a service and an application,(This involves transferring lots of thumbnails). Actually data size was around 500kb, and the IPC transaction buffer size is set to 1024KB. I am not sure why it exceeded the transaction buffer.

This also can occur, when you pass lot of data through intent extras

When you get this exception in your application, please analyze your code.

  1. Are you exchanging lot of data between your services and application?
  2. Using intents to share huge data, (for example, the user selects huge number of files from gallery share press share, the URIs of the selected files will be transferred using intents)
  3. receiving bitmap files from service
  4. waiting for android to respond back with huge data (for example, getInstalledApplications() when the user installed lot of applications)
  5. using applyBatch() with lot of operations pending

How to handle when you get this exception

If possible, split the big operation in to small chunks, for example, instead of calling applyBatch() with 1000 operations, call it with 100 each.

Do not exchange huge data (>1MB) between services and application

I dont know how to do this, but, Do not query android, which can return huge data :-)

Braise answered 9/10, 2012 at 22:10 Comment(22)
Suppose i am checking my .apk is installed or nor ? at time of installation... I am getting same exception while checking my package com.test.installedornot.My .apk size is more than 9MB then in that case how i will manage this exception?Lubricious
I'm getting this exception exactly during a call to getInstalledApplications. What can be done to solve this?Coliseum
@Coliseum This api is common and used broadly around android app. This exception really worries me somehow when I use this api.Isoniazid
@stan @ peacepassion Same with me as well. i am also getting this error and i am also reading installed apps. Please share if you people find and solution/turn around.Ignace
I can confirm your conclusions about limit being somewhere around 500KB but it's device specific, on some devices you can transfer almost the whole 1MB. I had this exception as well, so I did some investigating, and wrote a post that might be interesting read for people having this problem. nemanjakovacevic.net/blog/english/2015/03/24/…Subvene
@Coliseum , is your callback trace the same with the question? It seems that the question's trace is happened when activity resuming, but your trace should not , I thought.Halsted
@kidoher, of course the call stacks are different (because the apps are different), but why this should matter?Coliseum
@Stan, the stacks show that it happens when transacting a Intent to Activity, and crash when processing onResume(). But your matter is that when calls ` getInstalledApplications.However this question is nothing to do with getInstalledApplications`.Halsted
@kidoher, this question is about TransactionTooLargeException, no matter which calls are on the stack. Your point is not clear.Coliseum
I think 1Mb is right rather than 1MB - according this : developer.android.com/reference/android/os/…Selfemployed
I had this exception when using "context.getContentResolver().applyBatch(...)" for a list of operations. Thing is, I do want to apply a batch of operations, and I don't know what's the limit that should be used there. Is there a function to check it? Or at least a function that will return the max mem that can be used for the transaction ? Maybe I will do some heuristics...Asa
If you're finding it hard to track down exactly which state is causing your crash then you might find TooLargeTool useful.Daudet
@Coliseum @ Gem @ peacepassion did any of you guys find a solution to your problem ? cuz i'm facing the same issueDialogist
@mrid, I'm not sure what is your use case, but in the context of Android package manager the issue was fixed in Android 5.1+. Please check your software on updated OS.Coliseum
Additionally, from crashlytics insight: "This exception occurs when too much data is transferred via Parcels concurrently. The underlying 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.". Which means if multiple small transactions happen at the same time, this exception can be triggered too.Snipe
Also, you might want to assign your data to local variable after you are done with it and delete data from arguments with given key name. Otherwise even if you succeed on passing data between intents, os will eventually crash your app when you go background since it will refuse to store that big data.Phonography
@BurakDay Day can u explain how we can save data in local variable.Fader
@pallavirichhariya For a String type of variable; String localString = getIntent.getStringExtra("example"); getIntent.removeExtra("example") afterwardsPhonography
but if iam clearing that onsaveinstancestate.clear(); ....i will be able to get that variable???Fader
how to save full bundle and get it while restoring the state .... my bundle has arraylist ....and string also..Fader
Do you have to do that? I'm not sure if you can get it, however for that special case you could try to make a singleton and store what you pass inside it.Phonography
If I understand correctly, there is no solution but just make everything in putExtra() as small as possible. I cannot try catch the TransactionTooLargeException?Fireresistant
N
92

If you need to investigate which Parcel is causing your crash, you should consider trying TooLargeTool.

(I found this as a comment from @Max Spencer under the accepted answer and it was helpful in my case.)

Noctambulous answered 3/5, 2018 at 19:45 Comment(7)
Most underrated solution. This tool helps you narrow down the offending ActivitiesOvercurious
this tool is for kotlin :/ any alternative for java?Chandachandal
@maxwellnewage: seems like the latest version (0.2.1, 0.2.0 too) is currently not working in Java-only-applications. I had to use version 0.1.6 and it worked well thenDiscourage
Using this tool I detect that I was using huge size of bundles in my fragments. What I did is an extract the argument from the bundle and cleared the bundle using bundle.clear()Twinberry
This tool also helped me. The reason of TransactionTooLargeException was passing big-sized parameters to fragment in arguments (using Bundle). Now I pass parameters to fragment in constructor, and everything works fine.Arlaarlan
My project does not use AndroidX, so toolargetool worked for me only with theese changes: 1) implementation 'com.gu.android:toolargetool:0.2.1@aar' -> implementation 'com.gu.android:toolargetool:0.1.6@aar' 2) targetSdkVersion 28 -> targetSdkVersion 23Arlaarlan
@Arlaarlan Your solution seems wrong to me. #9245908Dolor
Q
49

This is not a definitive answer, but it may shed some light on the causes of a TransactionTooLargeException and help pinpoint the problem.

Although most answers refer to large amounts of data transferred, I see this exception being thrown incidentally after heavy scrolling and zooming and repeatedly opening an ActionBar spinner menu. The crash happens on tapping the action bar. (this is a custom mapping app)

The only data being passed around seem to be touches from the "Input Dispatcher" to the app. I think this cannot reasonably amount to anywhere near 1 mb in the "Transaction Buffer".

My app is running on a quad core 1.6 GHz device and uses 3 threads for heavylifting, keeping one core free for the UI thread. Furthermore, the app uses android:largeHeap, has 10 mb of unused heap left and has 100 mb of room left to grow the heap. So I wouldn't say it is a resource issue.

The crash is always immediately preceded by these lines:

W/InputDispatcher( 2271): channel ~ Consumer closed input channel or an error occurred.  events=0x9
E/InputDispatcher( 2271): channel ~ Channel is unrecoverably broken and will be disposed!
E/JavaBinder(28182): !!! FAILED BINDER TRANSACTION !!!

Which are not neccesarily printed in that order, but (as far as I checked) happen on the same millisecond.

And the stack trace itself, for clarity, is the same as in the question:

E/AndroidRuntime(28182): java.lang.RuntimeException: Adding window failed
..
E/AndroidRuntime(28182): Caused by: android.os.TransactionTooLargeException

Delving into the source code of android one finds these lines:

frameworks/base/core/jni/android_util_Binder.cpp:

case FAILED_TRANSACTION:
    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.
    jniThrowException(env, canThrowRemoteException
            ? "android/os/TransactionTooLargeException"
                    : "java/lang/RuntimeException", NULL);

To me it sounds like I'm possibly hitting this undocumented feature, where the transaction fails for other reasons than a Transaction being TooLarge. They should have named it TransactionTooLargeOrAnotherReasonException.

At this time I did not solve the issue, but if I find something useful I will update this answer.

update: it turned out my code leaked some file descriptors, the number of which is maximized in linux (typically 1024), and this seems to have triggered the exception. So it was a resource issue after all. I verified this by opening /dev/zero 1024 times, which resulted in all kinds of weird exceptions in UI related actions, including the exception above, and even some SIGSEGV's. Apparently failure to open a file/socket is not something which is handled/reported very cleanly throughout Android.

Quality answered 17/1, 2013 at 12:22 Comment(0)
S
44

The TransactionTooLargeException has been plaguing us for about 4 months now, and we've finally resolved the issue!

What was happening was we are using a FragmentStatePagerAdapter in a ViewPager. The user would page through and create 100+ fragments (its a reading application).

Although we manage the fragments properly in destroyItem(), in Androids implementation of FragmentStatePagerAdapter there is a bug, where it kept a reference to the following list:

private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();

And when the Android's FragmentStatePagerAdapter attempts to save the state, it will call the function

@Override
public Parcelable saveState() {
    Bundle state = null;
    if (mSavedState.size() > 0) {
        state = new Bundle();
        Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
        mSavedState.toArray(fss);
        state.putParcelableArray("states", fss);
    }
    for (int i=0; i<mFragments.size(); i++) {
        Fragment f = mFragments.get(i);
        if (f != null && f.isAdded()) {
            if (state == null) {
                state = new Bundle();
            }
            String key = "f" + i;
            mFragmentManager.putFragment(state, key, f);
        }
    }
    return state;
}

As you can see, even if you properly manage the fragments in the FragmentStatePagerAdapter subclass, the base class will still store an Fragment.SavedState for every single fragment ever created. The TransactionTooLargeException would occur when that array was dumped to a parcelableArray and the OS wouldn't like it 100+ items.

Therefore the fix for us was to override the saveState() method and not store anything for "states".

@Override
public Parcelable saveState() {
    Bundle bundle = (Bundle) super.saveState();
    bundle.putParcelableArray("states", null); // Never maintain any states from the base class, just null it out
    return bundle;
}
Studdard answered 3/4, 2017 at 20:11 Comment(8)
Of all the possibilities for this, for me this seemed only option. What is stored in the state that would allow it to get to this size? If the state is needed so badly that there is code to save it, how does this not cause other problems? ThanksHamlani
@Override public Parcelable saveState() { Bundle bundle = (Bundle) super.saveState(); if (bundle != null) { Parcelable[] states = bundle.getParcelableArray("states"); // Subset only last 3 states if (states != null) states = Arrays.copyOfRange(states, states.length > 3 ? states.length - 3 : 0, states.length - 1); bundle.putParcelableArray("states", states); } else bundle = new Bundle(); return bundle; }Allina
I just let only the last 3 states, check code above.Allina
After using your solution it also saving data in "states"Harlanharland
any idea how the same can be resolved in viewpager2 which uses fragmentStateAdapterYale
I don't understand. Why are you overriding the saveState when you are not doing anything in it. How about, just don't override it. Is there difference?Toscano
I faced same issue with ViewPager2 and FragmentStateAdapter the problem here is FragmentStateAdapter marked 'saveState()' as final and ViewPager2 class is final too, so we can not override the methods. however I was able to get rid of Transaction too large issue is by adding \android:saveEnabled="false" ' in XML entry for the View pager <androidx.viewpager2.widget.ViewPager2 android:saveEnabled="false" android:id="@+id/viewPager" android:layout_width="fill_parent" android:layout_height="fill_parent" />Indohittite
I had similar issue using view pager and state adapted where I was adding fragments dynamically. Removing BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT from state adapter solved my issueDasi
A
27

For those who bitterly disappointed in search of answer of why the TransactionTooLargeException apears, try to check how much information you save in instance state.

On compile/targetSdkVersion <= 23 we have only internal warning about large size of saved state, but nothing is crashed:

E/ActivityThread: App sent too much data in instance state, so it was ignored
    android.os.TransactionTooLargeException: data parcel size 713856 bytes
    at android.os.BinderProxy.transactNative(Native Method)
    at android.os.BinderProxy.transact(Binder.java:615)
    at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
    at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
    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:6044)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

But on compile/targetSdkVersion >= 24 we have real RuntimeException crash in this case:

java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 713860 bytes
    at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3737)
    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:6044)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
 Caused by: android.os.TransactionTooLargeException: data parcel size 713860 bytes
   at android.os.BinderProxy.transactNative(Native Method)
   at android.os.BinderProxy.transact(Binder.java:615)
   at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
   at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
   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:6044) 
   at java.lang.reflect.Method.invoke(Native Method) 
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 

What to do?

Save data in local database and keep only id's in instance state which you can use to retrieve this data.

Alignment answered 29/11, 2016 at 17:24 Comment(2)
is it possible to keep it as global parameter and use it later?Callisto
@Jitendraramoliya Yes, you can. That is exactly what I mean.Alignment
D
18

This exception is typically thrown when the app is being sent to the background.

So I've decided to use the data Fragment pattern to completely circumvent the onSavedInstanceState lifecycle. My solution also handles complex instance states and frees memory ASAP.

First I've created a simple Fargment to store the data:

package info.peakapps.peaksdk.logic;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;

/**
 * A neat trick to avoid TransactionTooLargeException while saving our instance state
 */

public class SavedInstanceFragment extends Fragment {

    private static final String TAG = "SavedInstanceFragment";
    private Bundle mInstanceBundle = null;

    public SavedInstanceFragment() { // This will only be called once be cause of setRetainInstance()
        super();
        setRetainInstance( true );
    }

    public SavedInstanceFragment pushData( Bundle instanceState )
    {
        if ( this.mInstanceBundle == null ) {
            this.mInstanceBundle = instanceState;
        }
        else
        {
            this.mInstanceBundle.putAll( instanceState );
        }
        return this;
    }

    public Bundle popData()
    {
        Bundle out = this.mInstanceBundle;
        this.mInstanceBundle = null;
        return out;
    }

    public static final SavedInstanceFragment getInstance(FragmentManager fragmentManager )
    {
        SavedInstanceFragment out = (SavedInstanceFragment) fragmentManager.findFragmentByTag( TAG );

        if ( out == null )
        {
            out = new SavedInstanceFragment();
            fragmentManager.beginTransaction().add( out, TAG ).commit();
        }
        return out;
    }
}

Then on my main Activity I circumvent the saved instance cycle completely, and defer the responsibility to my data Fragment. No need to use this on the Fragments themselves, since their state is added to the Activity's state automatically):

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    SavedInstanceFragment.getInstance( getFragmentManager() ).pushData( (Bundle) outState.clone() );
    outState.clear(); // We don't want a TransactionTooLargeException, so we handle things via the SavedInstanceFragment
}

What's left is simply to pop the saved instance:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(SavedInstanceFragment.getInstance(getFragmentManager()).popData());
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState( SavedInstanceFragment.getInstance( getFragmentManager() ).popData() );
}

Full details: http://www.devsbedevin.net/avoiding-transactiontoolargeexception-on-android-nougat-and-up/

Dugaid answered 28/8, 2017 at 12:24 Comment(10)
What happens if activity is destroyed when app is in background and you try to foreground activity?Kansas
@MasterDisaster in that case no state is saved because the process that holds the instance fragment has died.Dugaid
Rights, so this case works only with configuration change.Kansas
It works whenever the OS triggers onSavedState(), which happens on many cases. Configuration change is one. Switching apps and going to the background are another. And there are more.Dugaid
Perfect when you have many fragments already in a back stack and your Activity is Paused. Prevents that TTL exception that is otherwise impossible to stop and still retain the state.Catechumen
@Vaiden, in this case cache on disk is better, as I think it can restore data when application is recreated from background.Wrigley
I think this solution should be expanded to save data from different sources. Probably a HashMap with tags as keys and bundles as values..Wrigley
You should create this fragment first in activity, then in other places call it's methods. It receives FragmentManager fragmentManager as an argument, but it can vary in fragments. For instance, in ViewPager you may use getChildFragmentManager() which then cannot be used for getInstance() to get mInstanceBundle. So, use activity?.supportFragmentManager!! as a parameter. See my solution in https://mcmap.net/q/98498/-what-to-do-on-transactiontoolargeexception.Wrigley
I suppose, this solution won't work if your activities are removed after starting other activities. You can check this behaviour when turn on a checkbox Do not keep activities in Developer options (don't forget to uncheck then). In this case getFragmentManager() will be new and you won't get old data.Wrigley
You mentioned that "This exception is typically thrown when the app is being sent to the background." In my case this is not true, it happens all the time in foreground...Lanark
E
14

There isn't one specific cause of this problem.For me, in my Fragment class I was doing this:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);
    View rootView = inflater.inflate(R.layout.snacks_layout, container); //<-- notice the absence of the false argument
    return rootView;
}

instead of this:

View rootView = inflater.inflate(R.layout.softs_layout, container, false);
Enriqueenriqueta answered 4/10, 2015 at 10:46 Comment(1)
Wow! Thanks a lot! Would not have thought of this solution in a million years! I am still confused as to why improper way of inflating the view would cause such a havoc! Anyone has a valid explaination?Garnierite
H
11

It is important to understand that the transaction buffer is limited to 1 MB, regardless of device capabilities or app. This buffer is used with every API calls you make and is shared amongst all transactions an app is currently running.

I believe it also holds some specific object like parcels and such (Parcel.obtain()), so it's important to always match every obtain() with a recycle().

This error can easily happen on API calls returning a lot of data, even though the returned data is less than 1 MB (if other transactions are still running).

For example, the PackageManager.getInstalledApplication() call returns a list of all apps installed. Adding specific flags allows to retrieve a lot of extra data. Doing so is likely to fail, so it's recommended not to retrieve any extra data and retrieve those on a per-app basis.

However the call may still fail, so it's important to surround it with a catch and be able to retry if necessary.

As far as I know, there's no work-around to such issue except retrying and making sure to retrieve as little information as possible.

Hyman answered 23/11, 2013 at 16:27 Comment(2)
Thank you for info, that buffer is shared among all transactions within application!Gobang
If this were the case then why is it I am only getting on Android 4.4 phones and no where else. I think its more of a bug in 4.4 that I am unable to figure out why.Raseta
A
9

I too got this exception on a Samsung S3. I suspect 2 root causes,

  1. you have bitmaps that load and take up too much memory, use downsizing
  2. You have some drawables missing from the drawable-_dpi folders, android looks for them in drawable, and resizes them, making your setContentView suddenly jump and use a lot of memory.

Use DDMS and look at your heap as you play your app, that will give you some indication on which setcontentview is creating the issue.

I copied all the drawables across all folders to get rid of problem 2.

Issue is resolved.

Armelda answered 17/8, 2012 at 13:3 Comment(2)
The memory / bitmap exceptions usually look different. I have already seen a lot of them testing with Android 2.x - 4.x and the exceptions always looks different. But, who knows, maybe this is also related but specific to 4.x versions.Recipience
It's just a terrible exception, regarding to information, since it doesn't give any clue about where the problem comes from.Recipience
G
9

Add this to your Activity

@Override
protected void onSaveInstanceState(Bundle oldInstanceState) {
    super.onSaveInstanceState(oldInstanceState);
    oldInstanceState.clear();
}

It works for me hope also it will help you

Gradus answered 5/11, 2018 at 12:18 Comment(4)
I think, it is the most harmful hint. Why should we clear data that we want to restore in onCreate()?Wrigley
The implications of this code is that you end up NOT saving your instance state...Ruysdael
Bad solution. Don't do things like thatWham
I used it and later got bigger problems with onDestroy and onCreate.Molybdate
O
8

This may Happen because Activity "A" may have Fragments and when you navigate to Activity "B" .

then Activity Life Cycle of activty "A" will be

OnResume->OnPause()->OnSavedInsanceState()

here in OnSavedInsanceState may cause crash because it couldnt save state with to much data. so to try to clear the saveInsatnce of the Activity "A" by adding following code.

 @Override
protected void onSaveInstanceState(Bundle oldInstanceState) {
    super.onSaveInstanceState(oldInstanceState);
    if (oldInstanceState != null) {
        oldInstanceState.clear();
    }

}
Olivier answered 12/1, 2021 at 15:26 Comment(1)
but if screen rotate,this will cause to restart the applicationFerris
C
8

Our app also has this problem. After testing, it is found that when the application memory is insufficient and the activity is recycled, the system calls the onSaveInstanceState method to save a large amount of bundle data, and the data becomes large every time, and finally a TransactionTooLargeException error will be reported, so I think of this method should be able to solve this problem.

public final int MAX_BUNDLE_SIZE = 300;
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
     super.onSaveInstanceState(outState);
     long bundleSize = getBundleSize(outState);
     if (bundleSize > MAX_BUNDLE_SIZE * 1024) {
         outState.clear();
     }
}

private long getBundleSize(Bundle bundle) {
     long dataSize;
     Parcel obtain = Parcel.obtain();
     try {
         obtain.writeBundle(bundle);
         dataSize = obtain.dataSize();
     } finally {
        obtain.recycle();
     }
     return dataSize;
}
Catena answered 9/2, 2021 at 6:35 Comment(2)
my fear is that in order to get the bundle size, the app will use even more memory through the writeBundleEvening
Thank you. My issue with MiUI device is gone after such code fix was applied to all my activities and fragments. - I don't know for forever or not - but gone :-)Kt
E
4

So for us it was we were trying to send too large of an object through our AIDL interface to a remote service. The transaction size cannot exceed 1MB. The request is broken down into separate chunks of 512KB and sent one at a time through the interface. A brutal solution I know but hey - its Android :(

Eroto answered 19/9, 2012 at 21:21 Comment(0)
A
4

I faced with the same issue when I tried to send bitmap via Intent and at the same time when it happens I folded the application.

How it described in this article enter link description here it happens when an Activity is in the process of stopping, that means that the Activity was trying to send its saved state Bundles to the system OS for safe keeping for restoration later (after a config change or process death) but that one or more of the Bundles it sent were too large.

I solved it via hack by overriding onSaveInstanceState in my Activity:

@Override
protected void onSaveInstanceState(Bundle outState) {
    // super.onSaveInstanceState(outState);
}

and comment call super. It is a dirty hack but it is working perfectly. Bitmap was successfully sent without crashes. Hope this will help someone.

Alvera answered 31/5, 2018 at 7:26 Comment(0)
Q
3

Make sure that you do not put into Intent object data of large size. In my case I was adding String 500k size and then starting another activity. It always failed with this exception. I avoided sharing data between activities by using static variables of activities - you don't have to send them to Intent and then pulling from it.

What I had:

String html = new String();//some string of 500K data.
Intent intent = new Intent(MainActivity.this, PageWebView.class);
//this is workaround - I just set static variable and then access it from another    activity.
MainActivity.htmlBody = timelineDb.getHTMLBodyForTweet(tweet);
//This line was present and it actually failed with the same exception you had.
//intent.putExtra("com.gladimdim.offtie.webview", html);
Quern answered 14/1, 2013 at 22:40 Comment(1)
This is very bad idea. Using static variables in that way is a code smell. Also, try to run this code with "Don't keep activities" flag and press home after you navigate to PageWebView. After you open your activity again you will probably get a crash since MainActivity will be dead 100% with all its variables.Carrizales
H
3

Recently I also have encountered with an interesting case while working with Android's Contacts Provider.

I needed to load photos of contacts from internal contacts database and according to the system architecture all of this data are delivered by queries to Contacts Provider.

As it works as a separate application - all kinds of data transferring are performed by using Binder mechanism and so Binder buffer comes into play here.

My main mistake was that I didn't close the Cursor with blob data gotten from Contacts Provider, so that the memory allocated for the provider increased and this inflated the Binder buffer until I got tons of !!!FAILED BINDER TRANSACTION!!! messages in my LogCat output.

So the main idea is that when you work with external Content Providers and got Cursors from them, always close it when you finish to work with them.

Hulsey answered 3/6, 2013 at 11:39 Comment(0)
A
3

You have clear your old InstanceState from onSaveInstanceState method, and it will work well. I am using FragmentStatePagerAdapter for my viewpager so I keep below Override method into my parent activity for clear InstanceState.

@Override
protected void onSaveInstanceState(Bundle InstanceState) {
             super.onSaveInstanceState(InstanceState);
             InstanceState.clear();
}

I found this solution from here android.os.TransactionTooLargeException on Nougat

Amethyst answered 7/7, 2018 at 10:36 Comment(0)
V
2

In my case I get TransactionTooLargeException as a secondary crash after the native library crashed with SIGSEGV. The native library crash is not reported so I only receive TransactionTooLargeException.

Vinaigrette answered 11/8, 2015 at 21:32 Comment(0)
S
2

I got this in my syncadapter when trying to bulkInsert a large ContentValues[]. I decided to fix it as follows:

try {
    count = provider.bulkInsert(uri, contentValueses);
} catch (TransactionTooLarge e) {
    int half = contentValueses.length/2;
    count += provider.bulkInsert(uri, Arrays.copyOfRange(contentValueses, 0, half));
    count += provider.bulkInsert(uri, Arrays.copyOfRange(contentValueses, half, contentValueses.length));
}
Sounding answered 15/1, 2016 at 8:56 Comment(1)
What if the other fails ? You need to do more dividing, using a loop. Is there maybe a way to get the transaction size and get the max transaction size?Asa
T
2

For me it was also the FragmentStatePagerAdapter, however overriding saveState() did not work. Here's how I fixed it:

When calling the FragmentStatePagerAdapter constructor, keep a separate list of fragments within the class, and add a method to remove the fragments:

class PagerAdapter extends FragmentStatePagerAdapter {
    ArrayList<Fragment> items;

    PagerAdapter(ArrayList<Fragment> frags) {
        super(getFragmentManager()); //or getChildFragmentManager() or getSupportFragmentManager()
        this.items = new ArrayList<>();
        this.items.addAll(frags);
    }

    public void removeFragments() {
        Iterator<Fragment> iter = items.iterator();

        while (iter.hasNext()) {
            Fragment item = iter.next();
                getFragmentManager().beginTransaction().remove(item).commit();
                iter.remove();
            }
            notifyDataSetChanged();
        }
    }
    //...getItem() and etc methods...
}

Then in the Activity, save the ViewPager position and call adapter.removeFragments() in the overridden onSaveInstanceState() method:

private int pagerPosition;

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    //save other view state here
    pagerPosition = mViewPager.getCurrentItem();
    adapter.removeFragments();
}

Lastly, in the overridden onResume() method, re-instantiate the adapter if it isn't null. (If it's null, then the Activity is being opened for the first time or after the app has been killed off by Android, in which onCreate will do the adapter creation.)

@Override
public void onResume() {
    super.onResume();
    if (adapter != null) {
        adapter = new PagerAdapter(frags);
        mViewPager.setAdapter(adapter);
        mViewPager.setCurrentItem(currentTabPosition);
    }
}
Trouble answered 28/9, 2017 at 10:56 Comment(0)
F
2

This was happening in my app because I was passing a list of search results in a fragment's arguments, assigning that list to a property of the fragment - which is actually a reference to the same location in memory pointed to by the fragment's arguments - then adding new items to the list, which also changed the size of the fragment's arguments. When the activity is suspended, the base fragment class tries to save the fragment's arguments in onSaveInstanceState, which crashes if the arguments are larger than 1MB. For example:

private ArrayList<SearchResult> mSearchResults;

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    if (getArguments() != null && getArguments().getSerializable("SearchResults") != null) {
        mSearchResults = (ArrayList) getArguments().getSerializable("SearchResults");
    }
}

private void onSearchResultsObtained(ArrayList<SearchResult> pSearchResults) {

    // Because mSearchResults points to the same location in memory as the fragment's arguments
    // this will also increase the size of the arguments!
    mSearchResults.addAll(pSearchResults);
}

The easiest solution in this case was to assign a copy of the list to the fragment's property instead of assigning a reference:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    if (getArguments() != null && getArguments().getSerializable("SearchResults") != null) {

        // Copy value of array instead of reference
        mSearchResults = new ArrayList((ArrayList) getArguments().getSerializable("SearchResults"));
    }
}

An even better solution would be to not pass around so much data in the arguments.

I probably never would have found this without the help of this answer and TooLargeTool.

Fleeta answered 4/1, 2019 at 19:9 Comment(0)
I
2

I have also lived TransactionTooLargeException. Firstly I have worked on understand where it occurs. I know the reason why it occurs. Every of us know because of large content. My problem was like that and I solved. Maybe this solution can be useful for anybody. I have an app that get content from api. I am getting result from API in first screen and send it to second screen. I can send this content to second screen in successful. After second screen if I want to go third screen this exception occurs. Each of my screen is created from Fragment. I noticed that when I leave from second screen. It saves its bundle content. if this content is too large this exception happens. My solution is after I got content from bundle I clear it.

class SecondFragment : BaseFragment() {

    lateinit var myContent: MyContent

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        myContent = arguments?.getParcelable("mycontent")
        arguments?.clear()
    }
Inscribe answered 18/4, 2019 at 11:56 Comment(1)
While this is right (shame to me, I understood the same after a year), how will the fragment do if it recreates (screen rotation)?Wrigley
M
1

When I am dealing with the WebView in my app it happens. I think it's related to addView and UI resources. In my app I add some code in WebViewActivity like this below then it runs ok:

@Override
protected void onDestroy() {
    if (mWebView != null) {
        ((ViewGroup) mWebView.getParent()).removeView(mWebView);  
        mWebView.removeAllViews();  
        mWebView.destroy();
    }
    super.onDestroy();
}
Micronesian answered 9/12, 2014 at 6:10 Comment(0)
H
1

I found the root cause of this (we got both "adding window failed" and file descriptor leak as mvds says).

There is a bug in BitmapFactory.decodeFileDescriptor() of Android 4.4. It only occurs when inPurgeable and inInputShareable of BitmapOptions are set to true. This causes many problem in many places interact with files.

Note that the method is also called from MediaStore.Images.Thumbnails.getThumbnail().

Universal Image Loader is affected by this issue. Picasso and Glide seems to be not affected. https://github.com/nostra13/Android-Universal-Image-Loader/issues/1020

Halvorsen answered 17/6, 2015 at 10:37 Comment(0)
L
1

This one line of code in writeToParcel(Parcel dest, int flags) method helped me to get rid of TransactionTooLargeException.

dest=Parcel.obtain(); 

After this code only i am writing all data to the parcel object i.e dest.writeInt() etc.

Lanie answered 16/4, 2018 at 13:34 Comment(0)
M
1

Try to use EventBus or ContentProvider like solution.

If you are in the same process(normally all your activities would be), try to use EventBus, cause in process data exchange does NOT need a somewhat buffer, so you do not need to worry about your data is too large. (You can just use method call to pass data indeed, and EventBus hide the ugly things) Here is the detail:

// one side
startActivity(intentNotTooLarge);
EventBus.getDefault().post(new FooEvent(theHugeData));

// the other side
@Subscribe public void handleData(FooEvent event) { /* get and handle data */ }

If the two sides of Intent are not in the same process, try somewhat ContentProvider.


See TransactionTooLargeException

The Binder transaction failed because it was too large.

During a remote procedure call, the arguments and the return value of the call are transferred as Parcel objects stored in the Binder transaction buffer. If the arguments or the return value are too large to fit in the transaction buffer, then the call will fail and TransactionTooLargeException will be thrown.

Misfeasance answered 7/5, 2018 at 13:49 Comment(0)
C
1

I got a TransactionTooLargeException from a Stackoverflow error in a Android Espresso test. I found the stackoverflow error stack trace in the logs when I took off the Logcat filter for my app.

I'm guessing that Espresso caused the TransactionTooLargeException when trying to handle a really large exception stacktrace.

Clog answered 2/7, 2018 at 9:49 Comment(0)
E
1

Also i was facing this issue for Bitmap data passing from one activity to another but i make a solution by making my data as static data and this is working perfect for me

In activity first :

public static Bitmap bitmap_image;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_first);
   bitmap_image=mybitmap;
}

and in second activity :

 @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
   Bitmap mybitmap=first.bitmap_image;
}
Euhemerism answered 4/9, 2018 at 21:26 Comment(0)
W
1

@Vaiden answer helped me. I couldn't understand why short lists can raise this exceptions. I have many fragments and a couple of ViewPagers with lists. So, every time I started another activity or stopped a program (turned off a screen) I catched this exception (usually on Xiaomi).

I found that all fragments called their onSaveInstanceState() events, and in the end hosting activity called onSaveInstanceState() before onStop(). After that a crash occured. So, I understood that many short lists (10-100 Kb in size) can raise TransactionTooLargeException exception.

You may overcome this problem with writing data to a database and then get items by their ids. This way you can pass a list of ids to an Activity/Fragment.

But if you wish a temporary fast method, do this.

1) Create a retain-instance fragment, that will survive during activity recreation.

class SavedInstanceFragment : Fragment() {

    // This map will hold bundles from different sources (tag -> bundle).
    private lateinit var bundleMap: HashMap<String, Bundle?>


    // This method is only called once for this fragment.
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        retainInstance = true
        bundleMap = HashMap()
    }

    fun pushData(key: String, bundle: Bundle): SavedInstanceFragment {
        if (bundleMap[key] == null) {
            bundleMap[key] = bundle
        } else {
            bundleMap[key]!!.putAll(bundle)
        }
        return this
    }

    fun popData(key: String): Bundle? {
        val data = bundleMap[key]
        bundleMap[key] = null
        return data
    }

    fun removeData(key: String) {
        bundleMap.remove(key)
    }


    companion object {

        private val TAG = SavedInstanceFragment::class.java.simpleName

        // Create the fragment with this method in `onCreate()` of an activity.
        // Then you can get this fragment with this method again.
        fun getInstance(fragmentManager: FragmentManager): SavedInstanceFragment {
            var out = fragmentManager.findFragmentByTag(TAG) as SavedInstanceFragment?

            if (out == null) {
                out = SavedInstanceFragment()
                fragmentManager.beginTransaction().add(out, TAG).commit()
            }
            return out
        }
    }
}

2) In onCreate() of your activities that hold problem fragments, create this fragment. It will survive activity recreations. You should create it before other fragments are added to the FragmentManager, because this operation is asynchronous.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity)

    if (savedInstanceState == null) {
        SavedInstanceFragment.getInstance(supportFragmentManager)
    }

    ...
}

3) In every problem fragment add these lines. You should access a retain-instance fragment with getInstance(activity!!.supportFragmentManager) everywhere, so that you can find it inside FragmentManager. If use childFragmentManager as a parameter of getInstance(), then you will create another fragment and crash.

Also clear arguments after you read them and set a bundle, for instance, in onSaveInstanceState: arguments?.clear(). This is very important because arguments stay in memory when you create a new fragment. When you later return to the current fragment and rotate a screen, data won't be lost because they are already contained in a bundle and will be read in onCreate.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val bundle = if (savedInstanceState == null) {
        // Remove old data in order not to show wrong information.
        SavedInstanceFragment.getInstance(activity!!.supportFragmentManager).removeData(TAG)
        null
    } else {
        SavedInstanceFragment.getInstance(activity!!.supportFragmentManager).popData(TAG)
    }
    (bundle ?: arguments)?.run { // I access 'bundle' or 'arguments', depending if it is not first or first call of 'onCreate()'.
        token = getString(ARG_TOKEN)!!
        id = getInt(ARG_ID)
        items = getParcelableArrayList(ARG_ITEMS)
    }
}

override fun onSaveInstanceState(outState: Bundle) {
    // Create a copy of savedInstanceState and push to the retain-instance fragment.
    val bundle = (outState.clone() as Bundle).apply {
        putString(ARG_TOKEN, token)
        putInt(ARG_ID, id)
        putParcelableArrayList(ARG_ITEMS, items)
    }
    SavedInstanceFragment.getInstance(activity!!.supportFragmentManager).pushData(TAG, bundle)
    arguments?.clear() // Avoids an exception "java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size xxxxxxx bytes".
    super.onSaveInstanceState(outState)
}


companion object {

    private val TAG = YourFragment::class.java.simpleName

    private const val ARG_TOKEN = "ARG_TOKEN"
    private const val ARG_ID = "ARG_ID"
    private const val ARG_ITEMS = "ARG_ITEMS"

    fun newInstance(token: String, id: Int, items: ArrayList<Item>?) =
        YourFragment().apply {
            arguments = Bundle().apply {
                putString(ARG_TOKEN, token)
                putInt(ARG_ID, id)
                putParcelableArrayList(ARG_ITEMS, items)
            }
        }
}

Instead of persistent fragment you can use Singleton. Also read https://medium.com/@mdmasudparvez/android-os-transactiontoolargeexception-on-nougat-solved-3b6e30597345 for more information about libraries, solutions.

I suppose, this solution won't work if your activities are removed after starting other activities. You can check this behaviour when turn on a checkbox Do not keep activities in Developer options (don't forget to uncheck after). In this case getFragmentManager() will be new and you won't get old data. When you return from the new activity, you will get null in a bundle.

Wrigley answered 30/1, 2019 at 13:50 Comment(0)
T
1

If you converted Bitmap into Base64 in projects and save it to parcelable object you shuold resize bitmap with below code ,

replace png with jpeg and replace quality 100 to 75 or 60 :

bitmap.compress(Bitmap.CompressFormat.JPEG, 75, byteArrayOutputStream)

this solution works for me

Tother answered 17/6, 2019 at 9:27 Comment(0)
K
1

sometime Activity include some Fragment when Activityneed to totally recreate Fragments content, if the sportFragmentManager.fragments without clear history fragments

    val fragments = sportFragmentManager.fragments
    val transaction = sportFragmentManager.beginTransaction()
    for (frag in fragments){
        transaction.remove(frag)
    }
    transaction.commitAllowingStateLoss()

serveral times recreate Fragments the Activity will happen (debug use tooLargeTool)

 W/ActivityStopInfo: Bundle stats:
 W/ActivityStopInfo:   android:viewHierarchyState [size=2304]
 W/ActivityStopInfo:     android:views [size=2256]
 W/ActivityStopInfo:   android:support:fragments [size=519072]
 W/ActivityStopInfo: PersistableBundle stats:
 W/ActivityStopInfo:   [null]
Keil answered 15/7, 2019 at 10:2 Comment(0)
P
1

Issue is resolved by:

 Bundle bundle = new Bundle();
  bundle.putSerializable("data", bigdata);
...
  CacheHelper.saveState(bundle,"DATA");
  Intent intent = new Intent(mActivity, AActivity.class);
  startActivity(intent, bb);// do not put data to intent.

In Activity:
   @Override
   protected void onCreate(Bundle savedInstanceState) {
        Bundle bundle = CacheHelper.getInstance().loadState(Constants.DATA);
        if (bundle != null){
            Intent intent = getIntent();
            intent.putExtras(bundle);
        }
        getIntent().getExtra(..);
        ....
   }
   @Override
    protected void onDestroy() {
        super.onDestroy();
        CacheHelper.clearState("DATA");
    }

public class CacheHelper {

    public static void saveState(Bundle savedInstanceState, String name) {
        Bundle saved = (Bundle) savedInstanceState.clone();
        save(name, saved);
    }
    public Bundle loadState(String name) {

        Object object = load(name);
        if (object != null) {
            Bundle bundle = (Bundle) object;
            return bundle;
        }
        return null;
    }
    private static void save(String fileName, Bundle object) {
        try {
            String path = StorageUtils.getFullPath(fileName);
            File file = new File(path);
            if (file.exists()) {
                file.delete();
            }
            FileOutputStream fos = new FileOutputStream(path, false);

            Parcel p = Parcel.obtain(); //creating empty parcel object
            object.writeToParcel(p, 0); //saving bundle as parcel
            //parcel.writeBundle(bundle);
            fos.write(p.marshall()); //writing parcel to file

            fos.flush();
            fos.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static Bundle load(String fileName) {
        try {
            String path = StorageUtils.getFullPath(fileName);
            FileInputStream fis = new FileInputStream(path);

            byte[] array = new byte[(int) fis.getChannel().size()];
            fis.read(array, 0, array.length);

            Parcel parcel = Parcel.obtain(); //creating empty parcel object
            parcel.unmarshall(array, 0, array.length);
            parcel.setDataPosition(0);
            Bundle out = parcel.readBundle();
            out.putAll(out);

            fis.close();
            parcel.recycle();
            return out;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
public static void clearState(Activity ac) {
    String name = ac.getClass().getName();
    String path = StorageUtils.getFullPath(name);
    File file = new File(path);
    if (file.exists()) {
        file.delete();
    }
}
}
Prowel answered 21/8, 2020 at 12:52 Comment(0)
C
1

I got this error while uninstalling the app to which another app was making an IPC call to.

A hypothesis is that; as the "serving" app disappeared because of uninstallation, some transmit buffer might have been filled up, causing this error because nothing was no longer "popping things off" from the buffer.

If that was the case in your case, this problem might be nothing to worry about.

Colincolinson answered 6/10, 2022 at 14:7 Comment(0)
N
0

A solution would be for the app to write the ArrayList (or whatever object is causing the problem) to the file system, then pass a reference to that file (e.g., filename/path) via the Intent to the IntentService and then let the IntentService retrieve the file contents and convert it back to an ArrayList.

When the IntentService has done with the file, it should either delete it or pass the instruction back to the app via a Local Broadcast to delete the file that it created (passing back the same file reference that was supplied to it).

For more info see my answer to this related problem.

Nilsanilsen answered 6/11, 2016 at 21:34 Comment(0)
L
0

As Intents, Content Providers, Messenger, all system services like Telephone, Vibrator etc. utilize IPC infrastructure provider by Binder.Moreover the activity lifecycle callbacks also use this infrastructure.

1MB is the overall limit on all the binder transactions executed in the system at a particular moment.

In case there are lot of transactions happening when the intent is sent,it may fail even though extra data is not large. http://codetheory.in/an-overview-of-android-binder-framework/

Liar answered 12/6, 2017 at 6:58 Comment(0)
M
0

With so many places where TransactionTooLargeException can happen-- here's one more new to Android 8--a crash when someone merely starts to type into an EditText if the content is too big.

It's related to the AutoFillManager (new in API 26) and the following code in StartSessionLocked():

    mSessionId = mService.startSession(mContext.getActivityToken(),
            mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
            mCallback != null, flags, mContext.getOpPackageName());

If I understand correctly, this calls the autofill service-- passing the AutofillManagerClient within the binder. And when the EditText has a lot of content, it seems to cause the TTLE.

A few things may mitigate it (or did as I was testing anyway): Add android:importantForAutofill="noExcludeDescendants" in the EditText's xml layout declaration. Or in code:

EditText et = myView.findViewById(R.id.scriptEditTextView);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    et.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
}

A 2nd awful, terrible workaround might also be to override the performClick() and onWindowFocusChanged() methods to catch the error in a TextEdit subclass itself. But I don't think that's wise really...

Melchior answered 3/1, 2018 at 0:59 Comment(0)
M
0

For me TransactionTooLargeException occurred when i tried to send large bitmap image from one activity to another via intent. I solved this problem by using Application's Global Variables.

For example if you want to send large bitmap image from an activity A to to activity B, then store that bitmap image in global variable

((Global) this.getApplication()).setBitmap(bitmap);

then start activity B and read from global variable

Bitmap bitmap = ((Global) this.getApplication()).getBitmap();
Maize answered 24/1, 2018 at 12:17 Comment(0)
T
0

For me this error was coming in presenter. I made comment to onResume and write the same code in onStart and it worked for me.

 @Override
    public void onStart() {
        super.onStart();
        Goal goal = Session.getInstance(getContext()).getGoalForType(mMeasureType);
        if (goal != null && goal.getValue() > 0) {
            mCurrentValue = (int) goal.getValue();
            notifyPropertyChanged(BR.currentValue);
            mIsButtonEnabled.set(true);
        }
    }
   /* @Override
    public void onResume() {
        super.onResume();
        Goal goal = Session.getInstance(getContext()).getGoalForType(mMeasureType);
        if (goal != null && goal.getValue() > 0) {
            mCurrentValue = (int) goal.getValue();
            notifyPropertyChanged(BR.currentValue);
            mIsButtonEnabled.set(true);
        }
    }*/
Telegraphese answered 6/12, 2018 at 10:33 Comment(0)
A
0

In my case the reason of TransactionTooLargeException was that I sent big data to fragment in arguments (using Bundle), like this:

        var arguments = Bundle()
        arguments.putSerializable("argumentName", argumentValue)
        fragment.arguments = arguments

It works fine only if argumentValue has small size (for example Int or String), but if it has big size (for example list of DTO) - you can get TransactionTooLargeException. So now I pass parameters to fragment in constructor, and everything works fine.

PS Thanks to sulai for TooLargeTool

Arlaarlan answered 30/7, 2020 at 10:8 Comment(0)
I
0

I faced same issue with ViewPager2 and FragmentStateAdapter the problem here is FragmentStateAdapter marked 'saveState()' as final and ViewPager2 class is final too, so we can not override the methods as suggested in other answers making the existing answer not applicable.

In my case I was able to get rid of Transaction too large issue by not saving state of pager by adding \android:saveEnabled="false" ' in XML entry for the View pager

<androidx.viewpager2.widget.ViewPager2
    android:saveEnabled="false"
    android:id="@+id/viewPager"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />
Indohittite answered 15/3, 2021 at 13:55 Comment(0)
B
0

I have also come across this problem recently and after 2 days of reading all the solutions on this and other sites, I would like to share the cause of my problem and how I fixed it, as I haven't seen my problem in particular.

The fragments I use are:

  • FragmentA -> contains a recycler view with Bitmaps
  • FragmentB -> launches camera and returns image capture to Fragment A

FragmentB has the camera stuff so I send the Bitmap to FragmentA using previousBackStackEntry like this:

findNavController().run {
    previousBackStackEntry?.savedStateHandle?.set(KEY_REPORT_PHOTO, photo)
    popBackStack()
}

Finally, I use the Bitmap on FragmentA doing:

findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<Bitmap>(KEY_REPORT_PHOTO)
    ?.observe(viewLifecycleOwner) {
        it?.let { photo ->
            viewModel.addPhoto(photo)
            findNavController().currentBackStackEntry?.savedStateHandle?.set(KEY_REPORT_PHOTO, null)
        }
    }

Reading the information on this page, my first approach was to find out what was going on in onSaveInstanceState and try to delete the bitmaps from the recycler view that I thought were being saved when I closed the app and put it in the background.

Finally I realised that the problem was the Bitmap I was adding in the BackStackEntry of the navigation component and the solution was as easy as cleaning it after using the Bitmap in the FragmentA with this line:

findNavController().currentBackStackEntry?.savedStateHandle?.set(KEY_REPORT_PHOTO, null)
Boucher answered 17/7, 2022 at 1:0 Comment(0)
P
0

I don't know who may need this, but in case that you are using ViewPager2 with FragmentStateAdapter, and you have a large amount of fragments that also have their own Bundle data persistence, take care that you are not using Activity to instantiate FragmentStateAdapter, but your parent Fragment.

class PostPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {

Reason is that if you kill the fragment that hosts the ViewPager fragments, activity will still keep these fragments alive, which in time will consume memory and not only throw this exception but maybe many others.

This was at least issue on my end, and I figured it our using TooLargeTool along with debugging activity fragments.

Parrisch answered 17/7, 2023 at 17:40 Comment(1)
I use fragment as parameter in constructor of FragmentStateAdapter, but the issue still occurre :(Kt
L
-1

If you are using ViewPager2 FragmentStateAdapter with Navigation Component:

I was creating the adapter in onViewCreated(), but the view gets recreated every time you navigate back. For some reason, the old adapter wasn't detaching properly and increasing the bundle size until the error occurs. I debug it with TooLargeTool and the solution was to avoid the adapter recreation in onViewCreated().

In my fragment, I have the adapter variable:

var pagerAdapter:HomePagerAdapter?=null

Inside onViewCreated method, I create the adapter only once:

if(pagerAdapter == null){
  pagerAdapter = HomePagerAdapter(childFragmentManager, lifecycle, myContent)
}

To prevent IllegalArgumentException, I manually detach the adapter from the pager inside onDestroyView:

override fun onDestroyView() {
   pager.adapter = null
   super.onDestroyView()
}
Laflamme answered 27/5, 2021 at 19:42 Comment(0)
P
-1

add this code on method OnViewCreated

childFragmentManager.apply {
        logi("childFragmentManager = ", fragments.size)
        for (fragment in fragments) {
            logi(fragment)
            beginTransaction().remove(fragment).commitAllowingStateLoss()
        }
    }

In my case, the viewpager2 was create a lot of fragment, it's not clean up after the screen rotation, that's why the number of fragment increment too large (even not over 1kB) but this bug still occur. Hope this code can help someone.

Paleethnology answered 28/3, 2023 at 3:38 Comment(0)
C
-7

Another possible cause:

I had an activity that was starting itself in onResume()! This results in a ton of transactions and causes the phone (Galaxy S2) to completely freeze (no ANR or anything) and then to hard reset, which is kind of a huge bug in itself.

It would be interesting to see what happens on other phones with this code:

class MyActivity extends Activity
{
  // ...
  @Override
  void onResume()
  {
     super.onResume()
     startActivity(new Intent(this, MyActivity.class));
  }
}

I am not saying you should use that code.

Charbonneau answered 25/9, 2012 at 10:22 Comment(6)
This is not device related. You have just created an infinite loop. You create MyActivity that starts a new MyActivity when it's displayed that starts a new MyActivity and so on... What did you even want to achieve here?Nightlong
It shouldn't cause the phone to freeze and reboot.Charbonneau
@GaborPeto is right. This will create infinite loop.Grethel
Yes and it shouldn't cause the phone to freeze and reboot.Charbonneau
Timmmm wants us to reset our application instead of crash. Ha-ha! Remove this.Wrigley
How is everyone so bad at reading comprehension? I wasn't saying you should use the code in my answer. I was just saying that if you did have that code because of a mistake, it could cause a TransactionTooLargeException. And as an aside it also causes the phone to reboot which should not happen. Clear?Charbonneau

© 2022 - 2024 — McMap. All rights reserved.