TransactionTooLargeException üzerinde neler yapılır


239

Bende var TransactionTooLargeException. Tekrarlanamaz. Dokümanlarda diyor

Binder işlemi çok büyük olduğundan başarısız oldu.

Uzak yordam çağrısı sırasında, çağrının bağımsız değişkenleri ve dönüş değeri Ciltçi işlem arabelleğinde saklanan Parsel nesneleri olarak aktarılır. Bağımsız değişkenler veya dönüş değeri işlem arabelleğine sığmayacak kadar büyükse, çağrı başarısız olur ve TransactionTooLargeException atılır.

...

Uzak yordam çağrısı TransactionTooLargeException özel durumunu verdiğinde iki olası sonuç vardır. Müşteri isteğini hizmete gönderemedi (büyük olasılıkla bağımsız değişkenler işlem arabelleğine sığmayacak kadar büyükse) veya hizmet yanıtını istemciye geri gönderemedi (büyük olasılıkla dönüş değeri işlem arabelleğine sığmayacak kadar büyük).

...

Yani bir yerde bazı bilinmeyen sınırı aşan argümanlar geçiyorum ya da alıyorum. Nerede?

Yığın izleme yararlı bir şey göstermez:

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)

Görüşlerle ilgili gibi mi görünüyor? Bu, uzaktan yordam çağrısı ile nasıl ilişkilidir?

Belki önemli: Android sürümü: 4.0.3, Cihaz: HTC One X


Hayýr. Ama bir daha anlamadým. Canlı uygulamada hata izleyici var ve yaklaşık 3 hafta içinde sadece bir kez var. En azından sık görülmüyor. Belki de Android'de bir sorun açmaya değer ...
Ixx

Cevabım yok ama bu güvenilir bir şekilde Galaxy S2'imin sert sıfırlanmasına neden oluyor.
Timmmm

Bugün uygulamalardan birinde bu oldu. Bu sadece bir kez ve bir Galaxy S3 ile oldu. Bu sadece daha güçlü cihazlarla endişe verici görünüyor ilginç.
danwms

bu istisna API 15, developer.android.com/reference/android/os/… ' da eklenmiştir. Ve haritayı kaydırırken MapView içinde yeniden oluşturdum. gc hiç hafızam kalmadığını yazana kadar. (Birkaç dakika sürdü)
meh

İşlem arabelleği tüm cihazlarda 1 MB ile sınırlıdır ve bu tampon her işlemi eskidir. Böylece, cihaz ne kadar güçlü olursa, aynı 1MB arabelleğini tüketen aynı anda daha fazla işlem gerçekleştirebilir. Bununla birlikte, cevabınız bir cevap değil, bir yorumdur.
3c71 23:13

Yanıtlar:


158

Bu sorunla karşılaştım ve bir hizmet ve uygulama arasında çok fazla veri alışverişi yapıldığında (Bu, küçük resimlerin çoğaltılmasını içerir) buldum. Aslında veri boyutu 500kb civarındaydı ve IPC işlem arabellek boyutu 1024KB olarak ayarlandı. Neden işlem arabelleğini aştığından emin değilim.

Bu, amaç ekstralarından çok fazla veri ilettiğinizde de ortaya çıkabilir.

Bu özel durumu uygulamanızda aldığınızda, lütfen kodunuzu analiz edin.

  1. Hizmetleriniz ve uygulamanız arasında çok fazla veri alışverişi yapıyor musunuz?
  2. Büyük verileri paylaşmak için niyetleri kullanarak (örneğin, kullanıcı galeri paylaşımı basın paylaşımından çok sayıda dosya seçer, seçilen dosyaların URI'ları niyetler kullanılarak aktarılır)
  3. hizmetten bitmap dosyaları alma
  4. android'in büyük verilerle yanıt vermesini beklemek (örneğin, kullanıcı çok sayıda uygulama yüklediğinde getInstalledApplications ())
  5. bekleyen birçok işlemle camera.batch () kullanılıyor

Bu istisnayı aldığınızda nasıl davranılır?

Mümkünse büyük işlemi, küçük işlemlere ayırın, örneğin 1000 işlemle ApplyBatch () öğesini çağırmak yerine her birini 100 ile çağırın.

Hizmetler ve uygulama arasında devasa veri alışverişi (> 1 MB) yapmayın

Bunu nasıl yapacağımı bilmiyorum, ama, büyük veri döndürebilir android sorgulama :-)


1
Varsayalım .apk yüklü mü yoksa ne? kurulum sırasında ... benim paket com.test.installedornot.My .apk boyutu 9MB daha fazla olduğunu kontrol ederken aynı istisna alıyorum o zaman bu durumda nasıl bu istisnayı yönetecek?
DJhon

15
Bu istisnayı tam olarak bir çağrı sırasında alıyorum getInstalledApplications. Bunu çözmek için ne yapılabilir?
Stan

1
@Stan Bu api yaygın ve android uygulaması etrafında yaygın olarak kullanılmaktadır. Bu istisna, bu API'yi kullandığımda beni gerçekten bir şekilde endişelendiriyor.
peacepassion

7
Limitin 500KB civarında bir yerde olmanızla ilgili sonuçlarınızı doğrulayabilirim, ancak cihaza özgüdür, bazı cihazlarda neredeyse 1MB'yi aktarabilirsiniz. Ben de bu istisnayı vardı, bu yüzden bazı araştırmalar yaptım ve bu sorunu olan insanlar için ilginç bir okuma olabilir bir yazı yazdım. nemanjakovacevic.net/blog/english/2015/03/24/…
Nemanja Kovacevic

11
Tam olarak hangi durumun kilitlenmenize neden olduğunu bulmakta zorlanıyorsanız, TooLargeTool'u yararlı bulabilirsiniz .
Max Spencer

48

Hangi Parselin kilitlenmenize neden olduğunu araştırmanız gerekiyorsa, TooLargeTool'u denemeyi düşünmelisiniz. .

(Bunu kabul edilen cevap altında @Max Spencer'ın bir yorumu olarak buldum ve benim durumumda yardımcı oldu.)


9
En az çözüm. Bu araç, rahatsız edici Faaliyetleri daraltmanıza yardımcı olur
Kedar Paranjape

Sorunumu çözmeye yardımcı olan bu araç. Kurulumu ve kullanımı kolaydır.
Carlos

Bu araç kotlin için: / Java için herhangi bir alternatif?
maxwellnewage

2
@maxwellnewage: en son sürüm (0.2.1, 0.2.0 da) şu anda yalnızca Java uygulamalarında çalışmıyor gibi görünüyor . 0.1.6 sürümünü kullanmak zorundaydım ve o zaman iyi çalıştı
heisenberg

Bu aracı kullanarak parçalarımda büyük boyutta paketler kullandığımı tespit ettim. Yaptığım şey, argümanı paketten ayıklamak ve paketi kullanarak temizlemekbundle.clear()
EJ Chathuranga

41

Bu kesin bir cevap değildir, ancak a'nın nedenlerine biraz ışık tutabilir TransactionTooLargeExceptionve sorunun yerini belirlemeye yardımcı olabilir.

Çoğu yanıt aktarılan büyük miktarda veriyi ifade etse de, ağır kaydırma ve yakınlaştırma ve art arda bir ActionBar döndürücü menüsü açıldıktan sonra bu istisnanın tesadüfen atıldığını görüyorum. Kaza, işlem çubuğuna dokunulduğunda olur. (bu özel bir harita uygulamasıdır)

Etrafta aktarılan tek veri "Input Dispatcher" dan uygulamaya dokunur. Bu "İşlem Tamponu" 1 mb yakınındaki herhangi bir yere makul miktarda olamaz düşünüyorum.

Uygulamam dört çekirdekli 1.6 GHz cihazında çalışıyor ve ağırlaştırmak için 3 iş parçacığı kullanıyor ve bir çekirdeği UI iş parçacığı için serbest bırakıyor. Ayrıca, uygulama android kullanır: largeHeap, kullanılmayan yığın 10 mb kaldı ve yığın büyümek için 100 mb oda kaldı. Bu yüzden bunun bir kaynak sorunu olduğunu söyleyemem.

Çarpışmadan hemen önce şu satırlar gelir:

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

Bunlar bu sırayla basılmaz, ancak (kontrol ettiğim kadarıyla) aynı milisaniyede gerçekleşir.

Ve yığın izinin kendisi, netlik için, sorudakiyle aynıdır:

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

Android'in kaynak kodunu incelemek şu satırları bulur:

çerçeveler / baz / çekirdek / JNI'yı / 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);

Bana göre, işlemin TooLarge olmaktan başka nedenlerden dolayı başarısız olduğu bu belgesiz özelliğe isabet ediyorum gibi geliyor. Onlar adını vermelilerdi TransactionTooLargeOrAnotherReasonException.

Şu anda sorunu çözmedim, ancak yararlı bir şey bulursam bu cevabı güncelleyeceğim.

güncelleme: kodumun sayısı linux'da (genellikle 1024) maksimize edilen bazı dosya tanımlayıcılarını sızdırdı ve bu istisnayı tetikledi gibi görünüyor. Sonuçta bu bir kaynak sorunuydu. Bunu /dev/zero1024 kez açarak doğruladım , bu da yukarıdaki istisna dahil UI ile ilgili eylemlerde ve hatta bazı SIGSEGV'lerde her türlü garip istisnalara neden oldu. Görünüşe göre bir dosya / soket açılmaması, Android boyunca çok temiz bir şekilde ele alınan / bildirilen bir şey değildir.


36

TransactionTooLargeExceptionŞimdi 4 hakkında aydır bizi saran olmuştur ve nihayet sorunu çözdükten!

Ya bir kullanıyorsunuz edildi oluyordu FragmentStatePagerAdapterbir de ViewPager. Kullanıcı 100'den fazla parçaya sayfa oluşturur ve oluşturur (bu bir okuma uygulamasıdır).

Parçaları düzgün bir şekilde yönetmemize rağmen destroyItem(), Android uygulamasında FragmentStatePagerAdapteraşağıdaki listeye bir referans tuttuğu bir hata var:

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

Ve Android'in FragmentStatePagerAdapterdurumu kaydetmeye çalışması durumunda, işlevi çağırır.

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

Gördüğünüz gibi, FragmentStatePagerAdapteralt sınıftaki parçaları düzgün bir şekilde yönetseniz bile , temel sınıf yine de Fragment.SavedStateşimdiye kadar oluşturulan her bir parça için bir depolar . Bu TransactionTooLargeExceptiondizi, bir diziye atıldığında parcelableArrayve işletim sistemi 100+ öğeyi beğenmediğinde gerçekleşir.

Bu nedenle bizim için düzeltme saveState()yöntemi geçersiz kılmak ve hiçbir şey saklamak değildi"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;
}

benim için en iyi cevap. Çok teşekkür ederim
pavel

Bunun için tüm olasılıklardan, benim için bu sadece bir seçenek gibi görünüyordu. Bu boyuta ulaşmasına izin verecek durumda ne depolanır? Eyalete o kadar kötü ihtiyaç duyulursa, onu kaydetmek için kod vardır, bu başka sorunlara nasıl yol açmaz? Teşekkürler
Kenny

@Kenny ile aynı soru
Bay Tavşan

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

Sadece son 3 eyalete izin verdim, yukarıdaki kodu kontrol et.
Ramy Sabry

20

TransactionTooLargeException'ın neden ortaya çıktığını yanıtlamak için acı bir şekilde hayal kırıklığına uğrayanlar için, örnek durumda ne kadar bilgi kaydettiğinizi kontrol etmeye çalışın.

Compile / targetSdkVersion <= 23 üzerinde, yalnızca kaydedilmiş durumun büyük boyutu hakkında dahili uyarı var, ancak hiçbir şey çökmedi :

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)

Ancak compile / targetSdkVersion> = 24 üzerinde bu durumda gerçek RuntimeException çökmesi olur:

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) 

Ne yapalım?

Verileri yerel veritabanına kaydedin ve bu verileri almak için kullanabileceğiniz yalnızca kimliğini örnek durumunda tutun.


global parametre olarak tutmak ve daha sonra kullanmak mümkün müdür?
Jitendra ramoliya

@Jitendraramoliya Evet, yapabilirsin. Demek istediğim bu.
Yazon2006

13

Bu istisna genellikle uygulama arka plana gönderilirken atılır.

Bu yüzden, tamamen önlemek için veri Parçası yöntemini kullanmaya karar verdim. onSavedInstanceStae yaşam döngüsünü . Çözümüm karmaşık örnek durumlarını da işler ve belleği en kısa sürede serbest bırakır.

Önce verileri depolamak için basit bir Fargment oluşturdum:

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

Daha sonra ana faaliyetimde kaydedilen örnek döngüsünü tamamen atlatıyorum ve yanıt parçamı veri parçama erteliyorum. Bunu Parçaların kendisinde kullanmanıza gerek yoktur, durumlarının Faaliyetin durumuna otomatik olarak eklendiğinden emin olun):

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

Geriye kalan sadece kaydedilen örneği açmaktır:

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

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

Tüm ayrıntılar: http://www.devsbedevin.net/avoiding-transactiontoolargeexception-on-android-nougat-and-up/


1
Uygulama arka planda olduğunda ve etkinliği ön planlamaya çalıştığınızda etkinlik yok edilirse ne olur?
Usta Afet

@MasterDisaster bu durumda hiçbir durum kaydedilmez, çünkü örnek parçasını tutan işlem ölmüştür.
Vaiden

Haklar, bu nedenle bu durum yalnızca yapılandırma değişikliği ile çalışır.
Usta Afet

OS her tetiklendiğinde çalışır onSavedState(), bu birçok durumda olur. Yapılandırma değişikliği birdir. Uygulamaları değiştirmek ve arka plana gitmek başka bir şeydir. Dahası da var.
Vaiden

1
Farklı kaynaklardan veri kaydetmek için bu çözümün genişletilmesi gerektiğini düşünüyorum. Muhtemelen etiket olarak anahtar ve paket olarak değer içeren bir HashMap ..
CoolMind

11

Bu sorunun belirli bir nedeni yok. Benim için Fragment sınıfımda bunu yapıyordum:

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

bunun yerine:

View rootView = inflater.inflate(R.layout.softs_layout, container, false);

9

İşlem arabelleğinin, aygıt özelliklerine veya uygulamaya bakılmaksızın 1 MB ile sınırlı olduğunu anlamak önemlidir. Bu arabellek, yaptığınız her API çağrısı ile kullanılır ve bir uygulamanın şu anda çalışmakta olduğu tüm işlemler arasında paylaşılır.

Aynı zamanda parseller ve benzeri belirli bir nesneyi de tuttuğuna inanıyorum (Parcel.obtain()), bu yüzden her birini bir obtain()ile eşleştirmek önemlidir recycle().

Bu hata, döndürülen veriler 1 MB'den az olsa bile (diğer işlemler hala çalışıyorsa) çok fazla veri döndüren API çağrılarında kolayca meydana gelebilir.

Örneğin, PackageManager.getInstalledApplication()çağrı yüklü tüm uygulamaların bir listesini döndürür. Belirli bayraklar eklemek, fazladan fazla veri almayı sağlar. Bunu yapmanın başarısız olması muhtemeldir, bu nedenle fazladan veri almamanız ve bunları uygulama başına almamanız önerilir.

Ancak arama yine de başarısız olabilir, bu nedenle onu bir ile çevrelemek catchve gerekirse yeniden deneyebilmek önemlidir .

Bildiğim kadarıyla, yeniden denemek ve mümkün olduğunca az bilgi aldığınızdan emin olmak dışında böyle bir soruna geçici bir çözüm yoktur.


Bilgi için teşekkürler, arabellek uygulama içindeki tüm işlemler arasında paylaşılır!
Artem Mostyaev

1
Eğer durum buysa, neden sadece Android 4.4 telefonlara alıyorum ve başka bir yerde değilim. Ben 4.4 daha fazla bir hata nedenini anlayamıyorum düşünüyorum.
JPM

9

Samsung S3'te de bu istisnayı yaşadım. 2 temel nedenden şüpheleniyorum,

  1. çok fazla bellek yükleyen ve alan bitmap'leriniz var, küçültme kullanın
  2. Drawable-_dpi klasörlerinde eksik olan bazı çekmeceleriniz var, android bunları çekilebilir olarak arar ve yeniden boyutlandırır, setContentView'unuzu aniden atlar ve çok fazla bellek kullanır.

DDMS kullanın ve uygulamanızı oynatırken yığınıza bakın.

Sorun 2'den kurtulmak için tüm çekmeceleri tüm klasörler arasında kopyaladım.

Sorun çözüldü.


Bellek / bitmap istisnaları genellikle farklı görünür. Ben zaten Android 2.x - 4.x ile test bir sürü gördüm ve istisnalar her zaman farklı görünüyor. Ancak, kim bilir, belki de bu ilişkilidir, ancak 4.x sürümlerine özgüdür.
Ixx

10
Bu, bilgiyle ilgili korkunç bir istisnadır, çünkü sorunun nereden geldiğine dair herhangi bir ipucu vermez.
Ixx

Bence birkaç gün bitti, bulgularınız neler?
Denny

8

Bunu Etkinliğinize ekleyin

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

Benim için çalışıyor umarım sana da yardımcı olur


7
Bence en zararlı ipucu. Geri yüklemek istediğimiz verileri neden temizlemeliyiz onCreate()?
CoolMind

2
Bu kodun sonuçları, örnek durumunuzu
Justin

4

Bizim için AIDL arayüzümüzden uzak bir servise çok büyük bir nesne göndermeye çalışıyorduk. İşlem boyutu 1 MB'ı aşamaz. İstek 512KB değerinde ayrı parçalara bölünür ve arabirim yoluyla her seferinde bir tane gönderilir. Biliyorum acımasız bir çözüm ama hey - onun Android :(


4

Eski InstanceState'inizi onSaveInstanceState yönteminden temizlediniz ve iyi çalışacak. Benim viewpager için FragmentStatePagerAdapter kullanıyorum, bu yüzden açık InstanceState için benim ana faaliyet içine Override yöntemi aşağıda tutmak.

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

Bu çözümü buradan buldum android.os.TransactionTooLargeException Nougat üzerinde


Çok teşekkür ederim.
Andrain

Cevabınız için teşekkür ederim
Jatin Patel

3

Son zamanlarda Android'in Kişiler Sağlayıcısı ile çalışırken ilginç bir durumla karşılaştım .

Dahili kişi veritabanından kişilerin fotoğraflarını yüklemem gerekiyordu ve sistem mimarisine göre tüm bu veriler sorgularla Kişiler Sağlayıcısına dağıtılıyor.

Ayrı bir uygulama olarak çalıştığı için, her türlü veri aktarımı Binder mekanizması kullanılarak gerçekleştirilir ve böylece Binder tamponu burada devreye girer.

Benim asıl hata oldu ben değil yakınCursor sağlayıcı için ayrılan bellek artmış ve bu tonlarca var kadar Bağlayıcı tampon şişirilmiş böylece, İletişim Sağlayıcısı tarafından kazanılmış damla verilerle !!!FAILED BINDER TRANSACTION!!!benim LogCat çıkışında mesajlar.

Dolayısıyla ana fikir, harici İçerik Sağlayıcılarla Cursorçalıştığınızda ve onlardan aldığınızda, onlarla çalışmayı bitirdiğinizde her zaman kapatmanızdır.


3

Niyet yoluyla bitmap göndermeye çalıştığımda aynı sorunla karşılaştım ve aynı zamanda uygulamayı katladım.

Bu makalede nasıl açıklandığı, bağlantı açıklamasını buraya girin , bir Etkinlik durma sürecinde olduğunda gerçekleşir, yani Etkinlik daha sonra geri yükleme için güvenli bir şekilde saklamak üzere (yapılandırma değişikliğinden sonra) sistem işletim sistemine kayıtlı işletim sistemlerini göndermeye çalıştığı anlamına gelir. veya ölüm işlemek) ancak gönderdiği bir veya daha fazla Paketin çok büyük olması.

Etkinliğimde onSaveInstanceState'i geçersiz kılarak kesmek yoluyla çözdüm:

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

ve yorum süper arayın. Kirli bir hack ama mükemmel çalışıyor. Bitmap çökme olmadan başarıyla gönderildi. Umarım bu birine yardımcı olur.


2

Benim durumumda yerel kütüphane SIGSEGV ile çöktükten sonra ikincil bir çökme olarak TransactionTooLargeException alıyorum. Ben sadece TransactionTooLargeException almak yerel kütüphane kilitlenme bildirilmedi.


2

Ben büyük bir ContentValues ​​[] bulkInsert çalışırken bu benim syncadapter var. Aşağıdaki gibi düzeltmeye karar verdim:

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

2
Ya diğeri başarısız olursa? Bir döngü kullanarak daha fazla bölme yapmanız gerekir. İşlem boyutunu almanın ve maksimum işlem boyutunu almanın bir yolu var mı?
android geliştirici

2

Benim için de öyleydi FragmentStatePagerAdapter, ancak geçersiz kılma saveState()işe yaramadı. İşte nasıl düzelttim:

Yapıcıyı çağırırken, FragmentStatePagerAdaptersınıf içinde parçaların ayrı bir listesini tutun ve parçaları kaldırmak için bir yöntem ekleyin:

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

Ardından Activity, ViewPagerkonumu kaydedin ve adapter.removeFragments()geçersiz kılınan onSaveInstanceState()yöntemle çağırın :

private int pagerPosition;

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

Son olarak, geçersiz kılınan onResume()yöntemde, bağdaştırıcıyı yeniden başlatın null. (Bu buysa null, o zaman Activityuygulaması Android'de ölmüştü sonra hangi, ilk kez açıldığında veya ediliyor onCreateadaptör oluşturulmasını yapacağız.)

@Override
public void onResume() {
    super.onResume();
    if (adapter != null) {
        adapter = new PagerAdapter(frags);
        mViewPager.setAdapter(adapter);
        mViewPager.setCurrentItem(currentTabPosition);
    }
}

1

Büyük boyutlu Niyet nesnesi verilerine koymadığınızdan emin olun. Benim durumumda Dize 500k boyutu ekledim ve sonra başka bir etkinlik başlamıştı. Bu istisna dışında her zaman başarısız oldu. Etkinliklerin statik değişkenlerini kullanarak etkinlikler arasında veri paylaşımı yapmaktan kaçındım - bunları Niyet'e göndermeniz ve ardından çekmeniz gerekmez.

Ne vardı:

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

Bu çok kötü bir fikir. Statik değişkenleri bu şekilde kullanmak bir kod kokusudur. Ayrıca, "Etkinlikleri tutma" bayrağıyla bu kodu çalıştırmayı deneyin ve PageWebView öğesine gittikten sonra home tuşuna basın. Etkinliğinizi tekrar açtıktan sonra, MainActivity'nin tüm değişkenleriyle% 100 öleceği için muhtemelen bir kilitlenme yaşarsınız.
Kyrylo Zapylaiev

1

WebViewBenim app ile uğraşırken olur. Sanırım bununla ilgili addViewve kullanıcı arayüzü kaynakları. Benim app WebViewActivityaşağıdaki gibi bazı kod eklemek sonra Tamam çalışır:

@Override
protected void onDestroy() {
    if (mWebView != null) {
        ((ViewGroup) mWebView.getParent()).removeView(mWebView);  
        mWebView.removeAllViews();  
        mWebView.destroy();
    }
    super.onDestroy();
}

1

Bunun kök nedenini buldum (mvds'ın söylediği gibi "pencere ekleme başarısız oldu" ve dosya tanımlayıcı sızıntısı var).

Bir yoktur hata içinde BitmapFactory.decodeFileDescriptor()Android 4.4. Yalnızca inPurgeableve inInputShareable/ BitmapOptionsöğesi,true . Bu, birçok yerde dosyalar ile etkileşime giren birçok soruna neden olur.

Yöntemin ayrıca şu adresten çağrıldığını unutmayın: MediaStore.Images.Thumbnails.getThumbnail() .

Evrensel Görüntü Yükleyici bu sorundan etkilenir. Picasso ve Glide etkilenmemiş gibi görünüyor. https://github.com/nostra13/Android-Universal-Image-Loader/issues/1020


1

WriteToParcel (Parcel dest, int flags) yöntemindeki bu kod satırı TransactionTooLargeException özelliğinden kurtulmama yardımcı oldu.

dest=Parcel.obtain(); 

Bu koddan sonra sadece tüm verileri parsel nesnesine yazıyorum yani dest.writeInt () vb.


1

Çözümü kullanmaya EventBusveya ContentProviderbeğenmeye çalışın .

Aynı işlemdeyseniz (normalde tüm aktiviteleriniz olur), kullanmayı deneyin EventBus, işlemdeki veri alışverişinin neden bir ara belleğe ihtiyacı yoktur, bu nedenle verilerinizin çok büyük olduğundan endişelenmenize gerek yoktur. (Sadece veri aktarmak için yöntem çağrısı kullanabilirsiniz ve EventBus çirkin şeyleri gizleyin) İşte detay:

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

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

Niyetin iki tarafı aynı süreçte değilse, biraz deneyin ContentProvider.


TransactionTooLargeException konusuna bakın

Binder işlemi çok büyük olduğundan başarısız oldu.

Uzak yordam çağrısı sırasında, çağrının bağımsız değişkenleri ve dönüş değeri Ciltçi işlem arabelleğinde saklanan Parsel nesneleri olarak aktarılır. Bağımsız değişkenler veya dönüş değeri işlem arabelleğine sığmayacak kadar büyükse, çağrı başarısız olur ve TransactionTooLargeException atılır.


1

Android Espresso testinde bir Stackoverflow hatası TransactionTooLargeException aldım. Uygulamam için Logcat filtresini çıkardığımda günlüklerde stackoverflow hata yığını izini buldum.

Gerçekten büyük bir istisna stacktrace işlemeye çalışırken Espresso TransactionTooLargeException neden olduğunu tahmin ediyorum.


1

Biri şunları kullanabilir:

android:largeHeap="true"

Android Manifest'te uygulama etiketi altında.

Bu benim durumumdaki sorunu çözdü!


Benim durumumda ( onSaveInstantStatefaaliyetleri / parçaları çağırmak ve büyük listeleri kaydetmek nedeniyle ) yardımcı olmadı.
CoolMind

1
Bu kötü bir uygulama olarak kabul edilir, çünkü ilk etapta çok fazla veri kaydedilmesinin nedeniyle uğraşmıyorsunuz. Daha yeni cihazlarda, uygulama kilitlenir ve sınır çok daha küçüktür (256KB). Önce neden lot depoladığınızı araştırın ve azaltın.
Tim Kist

1

Ayrıca bir etkinlikten diğerine geçen Bitmap verileri için bu sorunla karşı karşıya kaldım ama verilerimi statik veri olarak yaparak bir çözüm üretiyorum ve bu benim için mükemmel çalışıyor

Öncelikle faaliyette:

public static Bitmap bitmap_image;

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

ve ikinci aktivitede:

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

1

Bu, uygulamamda bir parçanın argümanlarındaki arama sonuçlarının bir listesini geçiriyordum, bu listeyi parçanın bir özelliğine atayordum - aslında parçanın argümanlarının işaret ettiği bellekteki aynı konuma bir referans - sonra parçanın argümanlarının boyutunu da değiştiren listeye yeni öğeler. Etkinlik askıya alındığında, temel parça sınıfı, parçanın argümanlarını onSaveInstanceState dosyasına kaydetmeye çalışır ve argümanlar 1 MB'den büyükse çöker. Örneğin:

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

Bu durumda en kolay çözüm, bir referans atamak yerine listenin bir kopyasını parçanın özelliğine atamaktı:

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

Daha da iyi bir çözüm, argümanlarda bu kadar çok veri iletmemek olacaktır.

Muhtemelen bu cevap ve TooLargeTool yardımı olmadan bunu asla bulamazdım .


1

Ayrıca TransactionTooLargeException yaşadım. İlk olarak nerede olduğunu anlamak için çalıştım. Bunun nedenini biliyorum. Hepimiz büyük içerik nedeniyle biliyoruz. Sorunum böyleydi ve çözdüm. Belki bu çözüm herkes için yararlı olabilir. API'dan içerik alan bir uygulamam var. İlk ekranda API'dan sonuç alıyorum ve ikinci ekrana gönderiyorum. Bu içeriği başarılı bir şekilde ikinci ekrana gönderebilirim. İkinci ekrandan sonra üçüncü ekrana gitmek istersem bu istisna oluşur. Ekranımın her biri Fragment'tan oluşturuldu. İkinci ekrandan çıktığımda fark ettim. Paket içeriğini kaydeder. bu içerik çok büyükse bu istisna oluşur. Benim çözümüm, paketten içerik aldıktan sonra temizliyorum.

class SecondFragment : BaseFragment() {

    lateinit var myContent: MyContent

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        myContent = arguments?.getParcelable("mycontent")
        arguments?.clear()
    }

Bu doğru olsa da (benim için utanç verici, bir yıl sonra aynı şeyi anladım), parça yeniden yaratırsa (ekran döndürme) nasıl yapacak?
CoolMind

0

Uygulamanın ArrayList'i (veya soruna neden olan herhangi bir nesneyi) dosya sistemine yazması, daha sonra IntentService'in Niyeti aracılığıyla bu dosyaya (örneğin, dosya adı / yol) bir başvuru iletmesi ve IntentService'e izin vermesi bir çözüm olacaktır. dosya içeriğini alın ve onu bir ArrayList'e dönüştürün.

IntentService dosyayla yapıldığında, dosyayı silmeli veya oluşturduğu dosyayı silmek için talimatı bir Yerel Yayın aracılığıyla uygulamaya aktarmalıdır (dosyayla verilen aynı dosya referansını geri iletir).

Daha fazla bilgi için bu sorunla ilgili cevabımı inceleyin .


0

Amaçlar, İçerik Sağlayıcılar, Messenger, Telefon, Vibratör vb.Gibi tüm sistem hizmetleri Binder tarafından IPC altyapı sağlayıcısını kullanır, ayrıca aktivite yaşam döngüsü geri çağrıları da bu altyapıyı kullanır.

1MB, sistemde belirli bir anda yürütülen tüm bağlayıcı işlemlerin toplam sınırıdır.

Amaç gönderildiğinde çok fazla işlem olması durumunda, fazladan veri büyük olmasa bile başarısız olabilir. http://codetheory.in/an-overview-of-android-binder-framework/


0

TransactionTooLargeException'ın gerçekleşebileceği pek çok yerle - burada Android 8 için yeni bir tane var - birisi çok büyükse bir EditText'e yazmaya başladığında bir çökme.

İle ilgili olduğunu AutoFillManager (API 26 yeni) ve aşağıdaki kodu StartSessionLocked():

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

Doğru anlarsam, bu otomatik doldurma servisini çağırır - AutofillManagerClient'i cilt içinde geçirir. EditText çok fazla içeriğe sahip olduğunda, TTLE'ye neden olduğu görülüyor.

Birkaç şey onu hafifletebilir (veya yine de test ettiğim gibi): android:importantForAutofill="noExcludeDescendants"EditText'in xml mizanpaj bildirimine ekleyin . Veya kodda:

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

2. korkunç, korkunç bir geçici çözüm, TextEdit alt sınıfının kendisinde hatayı yakalamak için performClick()ve onWindowFocusChanged()yöntemlerini geçersiz kılmak olabilir . Ama bunun akıllıca olduğunu sanmıyorum ...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.