Was bei TransactionTooLargeException zu tun ist

Lesezeit: 11 Minuten

Was bei TransactionTooLargeException zu tun ist
Benutzer

Ich bekam ein TransactionTooLargeException. Nicht reproduzierbar. In den Unterlagen steht

Die Binder-Transaktion ist fehlgeschlagen, weil sie zu groß war.

Während eines entfernten Prozeduraufrufs werden die Argumente und der Rückgabewert des Aufrufs als Parcel-Objekte übertragen, die im Binder-Transaktionspuffer gespeichert sind. Wenn die Argumente oder der Rückgabewert zu groß sind, um in den Transaktionspuffer zu passen, schlägt der Aufruf fehl und TransactionTooLargeException wird ausgelöst.

Es gibt zwei mögliche Ergebnisse, wenn ein Remoteprozeduraufruf TransactionTooLargeException auslöst. Entweder konnte der Client seine Anfrage nicht an den Dienst senden (höchstwahrscheinlich, wenn die Argumente zu groß waren, um in den Transaktionspuffer zu passen), oder der Dienst konnte seine Antwort nicht an den Client zurücksenden (höchstwahrscheinlich, wenn der Rückgabewert zu groß, um in den Transaktionspuffer zu passen).

Irgendwo übergebe oder empfange ich also Argumente, die eine unbekannte Grenze überschreiten. Woher?

Der Stacktrace zeigt nichts Brauchbares:

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)

Es scheint mit Ansichten zusammenzuhängen? Wie hängt dies mit dem Remoteprozeduraufruf zusammen?

Vielleicht wichtig: Android-Version: 4.0.3, Gerät: HTC One X

  • Nein. Aber ich habe es nicht wieder bekommen. Habe Error Tracker in der Live-App und habe ihn nur dieses eine Mal in etwa 3 Wochen bekommen. Zumindest scheint es nicht oft vorzukommen. Vielleicht lohnt es sich, ein Problem bei Android zu eröffnen, obwohl …

    – Benutzer

    10. August 2012 um 18:31 Uhr

  • Ich habe keine Antwort, aber dies führt zuverlässig dazu, dass mein Galaxy S2 hart zurückgesetzt wird.

    – Timmm

    25. September 2012 um 10:15 Uhr

  • Das ist mir heute bei einer meiner Bewerbungen passiert. Dies ist auch nur einmal und mit einem Galaxy S3 passiert. Interessant ist, dass dies nur bei den leistungsstärkeren Geräten zu befürchten scheint.

    – Danwms

    26. September 2012 um 8:20 Uhr

  • diese Ausnahme wurde in API 15 hinzugefügt, developer.android.com/reference/android/os/… Und ich habe es in der MapView reproduziert, während ich auf der Karte herumscrollte. bis der GC schrieb, dass ich keine Erinnerung mehr habe. (Es dauerte ein paar Minuten)

    – meh

    9. Dezember 2012 um 13:45 Uhr

  • Der Transaktionspuffer ist auf allen Geräten auf 1 MB begrenzt, und dieser Puffer speichert jede Transaktion. Je leistungsstärker das Gerät ist, desto mehr Transaktionen kann es gleichzeitig ausführen, die alle denselben 1-MB-Puffer verbrauchen. Das heißt, Ihre Antwort ist keine Antwort, sondern ein Kommentar.

    – 3c71

    23. November 2013 um 16:21 Uhr


Wenn Sie untersuchen müssen, welches Paket Ihren Absturz verursacht, sollten Sie es versuchen TooLargeTool.

(Ich habe dies als Kommentar von @Max Spencer unter der akzeptierten Antwort gefunden und es war in meinem Fall hilfreich.)

  • Am meisten unterschätzte Lösung. Dieses Tool hilft Ihnen, die anstößigen Aktivitäten einzugrenzen

    – Kedar Paranjape

    7. Juni 2018 um 14:26 Uhr

  • Dieses Tool ist für Kotlin: / eine Alternative für Java?

    – maxwellnewage

    25. Juni 2019 um 16:09 Uhr

  • @maxwellnewage: scheint derzeit die neueste Version (0.2.1, auch 0.2.0) zu sein funktioniert nicht in Nur-Java-Anwendungen. Ich musste Version 0.1.6 verwenden und es hat damals gut funktioniert

    – Danni

    16. Januar 2020 um 17:56 Uhr


  • Mit diesem Tool stelle ich fest, dass ich große Bündel in meinen Fragmenten verwendet habe. Was ich getan habe, ist ein Extrahieren des Arguments aus dem Bündel und das Löschen des Bündels mit bundle.clear()

    – EJ Chathuranga

    24. Mai 2020 um 19:17 Uhr

  • Auch dieses Tool hat mir geholfen. Der Grund für TransactionTooLargeException war die Übergabe großer Parameter an Fragmente in Argumenten (unter Verwendung von Bundle). Jetzt übergebe ich Parameter an Fragment im Konstruktor, und alles funktioniert einwandfrei.

    – Maxim

    30. Juli 2020 um 10:00 Uhr


1646630595 107 Was bei TransactionTooLargeException zu tun ist
iko_wp

Die TransactionTooLargeException plagt uns jetzt seit ungefähr 4 Monaten und wir haben das Problem endlich gelöst!

Was passierte, war, dass wir a verwenden FragmentStatePagerAdapter in einem ViewPager. Der Benutzer würde durchblättern und mehr als 100 Fragmente erstellen (es ist eine Leseanwendung).

Obwohl wir die Fragmente ordentlich verwalten destroyItem()in der Android-Implementierung von FragmentStatePagerAdapter Es gibt einen Fehler, bei dem ein Verweis auf die folgende Liste beibehalten wurde:

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

Und wenn das Android ist FragmentStatePagerAdapter versucht, den Zustand zu speichern, wird die Funktion aufgerufen

@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;
}

Wie Sie sehen können, auch wenn Sie die Fragmente in der richtig verwalten FragmentStatePagerAdapter Unterklasse speichert die Basisklasse immer noch eine Fragment.SavedState für jedes einzelne Fragment, das jemals erstellt wurde. Die TransactionTooLargeException würde auftreten, wenn dieses Array in a ausgegeben wurde parcelableArray und das Betriebssystem würde es nicht mögen 100+ Elemente.

Daher bestand die Lösung für uns darin, die zu überschreiben saveState() Methode u nicht alles aufbewahren "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;
}

  • Von allen Möglichkeiten dafür schien mir dies die einzige Option. Was ist in dem Zustand gespeichert, der es ermöglichen würde, diese Größe zu erreichen? Wenn der Status so dringend benötigt wird, dass es Code gibt, um ihn zu speichern, wie verursacht dies dann keine anderen Probleme? Danke

    – Kenny

    24. November 2017 um 15:48 Uhr

  • @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; }

    – Ramy Sabry

    21. Februar 2018 um 12:20 Uhr


  • Ich lasse nur die letzten 3 Zustände, siehe Code oben.

    – Ramy Sabry

    21. Februar 2018 um 12:24 Uhr

  • Nachdem Sie Ihre Lösung verwendet haben, werden auch Daten in “Zuständen” gespeichert.

    – Pflaster

    2. März 2018 um 9:50 Uhr

  • Ich hatte das gleiche Problem mit ViewPager2 und FragmentStateAdapter. Das Problem hier ist, dass FragmentStateAdapter mit „saveState()“ als final gekennzeichnet ist und die ViewPager2-Klasse ebenfalls final ist, sodass wir die Methoden nicht überschreiben können. Ich konnte jedoch das Problem „Transaktion zu groß“ beseitigen, indem ich \android:saveEnabled=”false” ‘ im XML-Eintrag für den View-Pager

    – Entw

    15. März 2021 um 13:44 Uhr


Für diejenigen, die auf der Suche nach einer Antwort darauf, warum die TransactionTooLargeException erscheint, bitter enttäuscht sind, Versuchen Sie zu überprüfen, wie viele Informationen Sie im Instanzstatus speichern.

Beim Kompilieren/targetSdkVersion <= 23 haben wir nur eine interne Warnung über die Größe des gespeicherten Zustands, aber nichts ist abgestürzt:

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)

Aber beim Kompilieren/targetSdkVersion >= 24 haben wir einen echten RuntimeException-Absturz in diesem Fall:

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) 

Was ist zu tun?

Speichern Sie Daten in der lokalen Datenbank und bewahren Sie nur IDs im Instanzstatus auf, die Sie zum Abrufen dieser Daten verwenden können.

  • Von allen Möglichkeiten dafür schien mir dies die einzige Option. Was ist in dem Zustand gespeichert, der es ermöglichen würde, diese Größe zu erreichen? Wenn der Status so dringend benötigt wird, dass es Code gibt, um ihn zu speichern, wie verursacht dies dann keine anderen Probleme? Danke

    – Kenny

    24. November 2017 um 15:48 Uhr

  • @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; }

    – Ramy Sabry

    21. Februar 2018 um 12:20 Uhr


  • Ich lasse nur die letzten 3 Zustände, siehe Code oben.

    – Ramy Sabry

    21. Februar 2018 um 12:24 Uhr

  • Nachdem Sie Ihre Lösung verwendet haben, werden auch Daten in “Zuständen” gespeichert.

    – Pflaster

    2. März 2018 um 9:50 Uhr

  • Ich hatte das gleiche Problem mit ViewPager2 und FragmentStateAdapter. Das Problem hier ist, dass FragmentStateAdapter mit „saveState()“ als final gekennzeichnet ist und die ViewPager2-Klasse ebenfalls final ist, sodass wir die Methoden nicht überschreiben können. Ich konnte jedoch das Problem „Transaktion zu groß“ beseitigen, indem ich \android:saveEnabled=”false” ‘ im XML-Eintrag für den View-Pager

    – Entw

    15. März 2021 um 13:44 Uhr


Diese Ausnahme wird normalerweise ausgelöst, wenn die App an den Hintergrund gesendet wird.

Also habe ich mich entschieden, die Datenfragmentmethode zu verwenden, um das vollständig zu umgehen onSavedInstanceStae Lebenszyklus. Meine Lösung verarbeitet auch komplexe Instanzzustände und gibt Speicher so schnell wie möglich frei.

Zuerst habe ich ein einfaches Fargment erstellt, um die Daten zu speichern:

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;
    }
}

Dann umgehe ich bei meiner Hauptaktivität den gespeicherten Instanzzyklus vollständig und verschiebe die Verantwortung auf mein Datenfragment. Dies muss nicht für die Fragmente selbst verwendet werden, da ihr Status automatisch zum Status der Aktivität hinzugefügt wird):

@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
}

Was übrig bleibt, ist einfach, die gespeicherte Instanz zu öffnen:

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

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

Alle Einzelheiten: http://www.devsbedevin.net/avoiding-transactiontoolargeexception-on-android-nougat-and-up/

  • Was passiert, wenn die Aktivität zerstört wird, während sich die App im Hintergrund befindet und Sie versuchen, die Aktivität in den Vordergrund zu rücken?

    – Master-Katastrophe

    1. Oktober 2017 um 8:56 Uhr

  • @MasterDisaster In diesem Fall wird kein Status gespeichert, da der Prozess, der das Instanzfragment enthält, gestorben ist.

    – Vaiden

    1. Oktober 2017 um 9:24 Uhr

  • Rechte, daher funktioniert dieser Fall nur mit Konfigurationsänderung.

    – Master-Katastrophe

    2. Oktober 2017 um 11:12 Uhr

  • Es funktioniert immer, wenn das Betriebssystem auslöst onSavedState(), was in vielen Fällen vorkommt. Konfigurationsänderung ist eine. Das Wechseln von Apps und das Wechseln in den Hintergrund sind eine andere. Und es gibt noch mehr.

    – Vaiden

    2. Oktober 2017 um 13:41 Uhr

  • Ich denke, diese Lösung sollte erweitert werden, um Daten aus verschiedenen Quellen zu speichern. Wahrscheinlich eine HashMap mit Tags als Schlüssel und Bundles als Werte.

    – CoolMind

    20. Dezember 2018 um 15:53 ​​Uhr

963120cookie-checkWas bei TransactionTooLargeException zu tun ist

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy