Apa yang harus dilakukan pada TransactionTooLargeException

239

Saya mendapat TransactionTooLargeException. Tidak dapat direproduksi. Dalam dokumen itu tertulis

Transaksi Binder gagal karena terlalu besar.

Selama panggilan prosedur jarak jauh, argumen dan nilai balik panggilan ditransfer sebagai objek Parcel yang disimpan dalam buffer transaksi Binder. Jika argumen atau nilai pengembalian terlalu besar untuk muat dalam buffer transaksi, maka panggilan akan gagal dan TransactionTooLargeException akan dibuang.

...

Ada dua kemungkinan hasil ketika panggilan prosedur jarak jauh melempar TransactionTooLargeException. Entah klien tidak dapat mengirim permintaannya ke layanan (kemungkinan besar jika argumen terlalu besar untuk muat dalam buffer transaksi), atau layanan tidak dapat mengirim responsnya kembali ke klien (kemungkinan besar jika nilai pengembalian adalah terlalu besar untuk muat dalam buffer transaksi).

...

Jadi di suatu tempat saya melewati atau menerima argumen yang melampaui batas yang tidak diketahui. Dimana?

Stacktrace tidak menunjukkan sesuatu yang berguna:

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)

Tampaknya terkait dengan pandangan? Bagaimana ini terkait dengan panggilan prosedur jarak jauh?

Mungkin penting: Versi Android: 4.0.3, Perangkat: HTC One X

Ixx
sumber
Tidak. Tapi saya tidak mendapatkannya lagi. Memiliki pelacak kesalahan di aplikasi langsung dan mendapatkannya hanya satu kali dalam waktu sekitar 3 minggu. Setidaknya itu tidak sering terjadi. Mungkin layak untuk membuka masalah di Android meskipun ...
Ixx
Saya tidak punya jawaban tetapi ini andal menyebabkan Galaxy S2 saya sulit diatur ulang.
Timmmm
Saya baru saja mengalami ini di salah satu aplikasi saya hari ini. Ini juga hanya terjadi sekali dan dengan Galaxy S3. Sangat menarik bahwa ini tampaknya hanya untuk memahami dengan perangkat yang lebih kuat.
danwms
pengecualian itu ditambahkan di API 15, developer.android.com/reference/android/os/... Dan saya telah mereproduksi di MapView sambil menggulirkan peta. sampai gc menulis bahwa saya tidak memiliki ingatan yang tersisa. (Butuh saya beberapa menit)
meh
Buffer transaksi dibatasi hingga 1MB di semua perangkat, dan buffer ini lebih lama dari setiap transaksi. Jadi semakin kuat perangkat, semakin banyak transaksi yang dilakukan secara bersamaan, yang semuanya mengkonsumsi buffer 1MB yang sama. Yang mengatakan, jawaban Anda bukanlah jawaban tetapi komentar.
3c71

Jawaban:

158

Saya mengalami masalah ini, dan saya menemukan bahwa ketika ada sejumlah besar data yang dipertukarkan antara layanan dan aplikasi, (Ini melibatkan transfer banyak thumbnail). Sebenarnya ukuran data sekitar 500kb, dan ukuran buffer transaksi IPC diatur ke 1024KB. Saya tidak yakin mengapa itu melebihi buffer transaksi.

Ini juga dapat terjadi, ketika Anda melewatkan banyak data melalui ekstra maksud

Ketika Anda mendapatkan pengecualian ini di aplikasi Anda, silakan menganalisis kode Anda.

  1. Apakah Anda bertukar banyak data antara layanan dan aplikasi Anda?
  2. Menggunakan maksud untuk berbagi data yang sangat besar, (misalnya, pengguna memilih sejumlah besar file dari berbagi pers galeri, URI dari file yang dipilih akan ditransfer menggunakan maksud)
  3. menerima file bitmap dari layanan
  4. menunggu android untuk merespons kembali dengan data yang sangat besar (misalnya, getInstalledApplications () ketika pengguna menginstal banyak aplikasi)
  5. menggunakan applyBatch () dengan banyak operasi yang tertunda

Cara menangani ketika Anda mendapatkan pengecualian ini

Jika memungkinkan, bagi operasi besar menjadi potongan kecil, misalnya, alih-alih memanggil applyBatch () dengan 1000 operasi, panggillah dengan masing-masing 100.

Jangan bertukar data besar (> 1MB) antara layanan dan aplikasi

Saya tidak tahu bagaimana melakukan ini, tetapi, Jangan kueri android, yang dapat mengembalikan data sangat besar :-)

Durairaj Packirisamy
sumber
1
Misalkan saya memeriksa .apk saya diinstal atau tidak? pada saat instalasi ... Saya mendapatkan pengecualian yang sama saat memeriksa paket saya com.test.installedornot.My. Ukuran .apk lebih dari 9MB lalu dalam hal ini bagaimana saya akan mengelola pengecualian ini?
DJhon
15
Saya menerima pengecualian ini saat panggilan ke getInstalledApplications. Apa yang bisa dilakukan untuk menyelesaikan ini?
Stan
1
@Stan Api ini adalah umum dan digunakan secara luas di sekitar aplikasi Android. Pengecualian ini benar-benar membuat saya khawatir ketika saya menggunakan api ini.
peacepassion
7
Saya dapat mengkonfirmasi kesimpulan Anda tentang batas berada di suatu tempat di sekitar 500KB tapi itu khusus perangkat, pada beberapa perangkat Anda dapat mentransfer hampir seluruh 1MB. Saya memiliki pengecualian ini juga, jadi saya melakukan investigasi, dan menulis posting yang mungkin menarik dibaca untuk orang yang memiliki masalah ini. nemanjakovacevic.net/blog/english/2015/03/24/...
Nemanja Kovacevic
11
Jika Anda merasa sulit untuk melacak secara tepat keadaan mana yang menyebabkan kerusakan Anda, maka Anda mungkin menemukan TooLargeTool berguna.
Max Spencer
48

Jika Anda perlu menyelidiki Paket mana yang menyebabkan kerusakan Anda, Anda harus mempertimbangkan untuk mencoba TooLargeTool .

(Saya menemukan ini sebagai komentar dari @ Max Spencer di bawah jawaban yang diterima dan itu membantu dalam kasus saya.)

sulai
sumber
9
Solusi yang paling diremehkan. Alat ini membantu Anda mempersempit Aktivitas yang menyinggung
Kedar Paranjape
Alat ini yang membantu menyelesaikan masalah saya. Mudah dipasang dan digunakan.
Carlos
alat ini untuk kotlin: / ada alternatif untuk java?
maxwellnewage
2
@maxwellnewage: sepertinya versi terbaru (0.2.1, 0.2.0 juga) saat ini tidak berfungsi di aplikasi khusus Java. Saya harus menggunakan versi 0.1.6 dan bekerja dengan baik
heisenberg
Dengan menggunakan alat ini, saya mendeteksi bahwa saya menggunakan bundel dalam ukuran yang sangat besar. Apa yang saya lakukan adalah mengekstrak argumen dari bundel dan membersihkan bundel menggunakanbundle.clear()
EJ Chathuranga
41

Ini bukan jawaban yang pasti, tetapi mungkin menjelaskan beberapa penyebab a TransactionTooLargeExceptiondan membantu menunjukkan masalah.

Meskipun sebagian besar jawaban merujuk pada sejumlah besar data yang ditransfer, saya melihat pengecualian ini dilemparkan secara tidak sengaja setelah pengguliran dan pembesaran yang berat dan berulang kali membuka menu pemintal ActionBar. Kecelakaan terjadi saat mengetuk bilah tindakan. (ini adalah aplikasi pemetaan khusus)

Satu-satunya data yang diedarkan tampaknya adalah sentuhan dari "Input Dispatcher" ke aplikasi. Saya pikir ini tidak cukup untuk mencapai 1 mb di "Penyangga Transaksi".

Aplikasi saya berjalan pada perangkat quad core 1.6 GHz dan menggunakan 3 utas untuk pengangkat beban, menjaga satu inti gratis untuk utas UI. Selain itu, aplikasi ini menggunakan android: largeHeap, memiliki 10 mb tumpukan kiri yang tidak digunakan dan memiliki 100 mb ruang tersisa untuk menumbuhkan tumpukan. Jadi saya tidak akan mengatakan itu adalah masalah sumber daya.

Kecelakaan selalu segera didahului oleh baris-baris ini:

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

Yang tidak perlu dicetak dalam urutan itu, tetapi (sejauh yang saya periksa) terjadi pada milidetik yang sama.

Dan jejak stack itu sendiri, untuk kejelasan, sama seperti pada pertanyaan:

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

Menggali kode sumber android menemukan baris-baris ini:

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

Bagi saya kedengarannya seperti saya mungkin memukul fitur tidak berdokumen ini, di mana transaksi gagal karena alasan lain selain Transaksi yang terlalu besar. Mereka seharusnya menamainya TransactionTooLargeOrAnotherReasonException.

Saat ini saya tidak menyelesaikan masalah, tetapi jika saya menemukan sesuatu yang bermanfaat saya akan memperbarui jawaban ini.

update: ternyata kode saya membocorkan beberapa deskriptor file, yang jumlahnya dimaksimalkan di linux (biasanya 1024), dan ini tampaknya telah memicu pengecualian. Jadi itu adalah masalah sumber daya. Saya memverifikasi ini dengan membuka /dev/zero1024 kali, yang menghasilkan semua jenis pengecualian aneh dalam tindakan terkait UI, termasuk pengecualian di atas, dan bahkan beberapa SIGSEGV. Rupanya kegagalan untuk membuka file / socket bukanlah sesuatu yang ditangani / dilaporkan dengan sangat bersih di seluruh Android.

mvds
sumber
36

The TransactionTooLargeExceptiontelah mengganggu kami selama sekitar 4 bulan sekarang, dan kami akhirnya menyelesaikan masalah!

Apa yang terjadi adalah kita menggunakan FragmentStatePagerAdaptera ViewPager. Pengguna akan membuka halaman dan membuat 100+ fragmen (ini adalah aplikasi membaca).

Meskipun kami mengelola fragmen dengan benar destroyItem(), dalam implementasi Android FragmentStatePagerAdapterada bug, di mana ia menyimpan referensi ke daftar berikut:

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

Dan ketika Android FragmentStatePagerAdaptermencoba menyelamatkan negara, itu akan memanggil fungsi

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

Seperti yang Anda lihat, bahkan jika Anda mengelola fragmen di FragmentStatePagerAdaptersubclass dengan benar, kelas dasar masih akan menyimpan Fragment.SavedStateuntuk setiap fragmen yang pernah dibuat. Itu TransactionTooLargeExceptionakan terjadi ketika array itu dibuang ke parcelableArraydan OS tidak akan menyukainya 100+ item.

Oleh karena itu perbaikan bagi kami adalah mengganti saveState()metode dan tidak menyimpan apa pun untuk "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;
}
IK828
sumber
jawaban terbaik untukku Terima kasih banyak
pavel
Dari semua kemungkinan untuk ini, bagi saya ini sepertinya satu-satunya pilihan. Apa yang disimpan dalam kondisi yang memungkinkannya mencapai ukuran ini? Jika keadaan sangat dibutuhkan sehingga ada kode untuk menyimpannya, bagaimana ini tidak menyebabkan masalah lain? Terima kasih
Kenny
Pertanyaan yang sama dengan @Kenny
Tn. Rabbit
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
Saya hanya membiarkan 3 negara terakhir, periksa kode di atas.
Ramy Sabry
20

Bagi mereka yang sangat kecewa mencari jawaban mengapa TransactionTooLargeException muncul, cobalah untuk memeriksa berapa banyak informasi yang Anda simpan dalam keadaan contoh.

Pada kompilasi / targetSdkVersion <= 23 kami hanya memiliki peringatan internal tentang ukuran besar kondisi yang disimpan, tetapi tidak ada yang macet:

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)

Tetapi pada compile / targetSdkVersion> = 24 kita memiliki crash RuntimeException nyata dalam kasus ini:

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) 

Apa yang harus dilakukan?

Simpan data dalam database lokal dan pertahankan hanya status id yang dapat Anda gunakan untuk mengambil data ini.

Yazon2006
sumber
apakah mungkin menyimpannya sebagai parameter global dan menggunakannya nanti?
Jitendra ramoliya
@Jendendraramoliya Ya, Anda bisa. Itulah tepatnya yang saya maksud.
Yazon2006
13

Pengecualian ini biasanya dilemparkan ketika aplikasi sedang dikirim ke latar belakang.

Jadi saya telah memutuskan untuk menggunakan metode Fragmen data untuk sepenuhnya menghindari onSavedInstanceStaesiklus hidup. Solusi saya juga menangani status instance yang kompleks dan membebaskan memori ASAP.

Pertama, saya telah membuat Fargment sederhana untuk menyimpan 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;
    }
}

Kemudian pada Kegiatan utama saya, saya menghindari siklus instance yang disimpan sepenuhnya, dan menunda tanggung jawab untuk Fragmen data saya. Tidak perlu menggunakan ini pada Fragmen itu sendiri, sice negara mereka ditambahkan ke keadaan Aktivitas secara otomatis):

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

Yang tersisa hanyalah menghapus contoh yang disimpan:

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

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

Detail lengkap: http://www.devsbedevin.net/avoiding-transactiontoolargeexception-on-android-nougat-and-up/

Vaiden
sumber
1
Apa yang terjadi jika aktivitas dihancurkan ketika aplikasi di latar belakang dan Anda mencoba untuk latar depan aktivitas?
Master Disaster
@MasterDisaster dalam kasus itu tidak ada keadaan yang disimpan karena proses yang menyimpan instance instance telah mati.
Vaiden
Hak, jadi kasus ini hanya berfungsi dengan perubahan konfigurasi.
Master Disaster
Ini bekerja setiap kali OS memicu onSavedState(), yang terjadi pada banyak kasus. Perubahan konfigurasi adalah satu. Beralih aplikasi dan pergi ke latar belakang adalah hal lain. Dan masih ada lagi.
Vaiden
1
Saya pikir solusi ini harus diperluas untuk menghemat data dari berbagai sumber. Mungkin HashMap dengan tag sebagai kunci dan bundel sebagai nilai ..
CoolMind
11

Tidak ada satu penyebab spesifik masalah ini. Bagi saya, di kelas Fragmen saya, saya melakukan ini:

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

alih-alih ini:

View rootView = inflater.inflate(R.layout.softs_layout, container, false);
Ojonugwa Jude Ochalifu
sumber
9

Penting untuk dipahami bahwa buffer transaksi dibatasi hingga 1 MB, terlepas dari kemampuan atau aplikasi perangkat. Buffer ini digunakan dengan setiap panggilan API yang Anda buat dan dibagikan di antara semua transaksi yang sedang dijalankan aplikasi.

Saya percaya itu juga memegang beberapa objek spesifik seperti parsel dan semacamnya (Parcel.obtain()), jadi penting untuk selalu mencocokkan setiap obtain()dengan a recycle().

Kesalahan ini dapat dengan mudah terjadi pada panggilan API yang mengembalikan banyak data, meskipun data yang dikembalikan kurang dari 1 MB (jika transaksi lain masih berjalan).

Misalnya, PackageManager.getInstalledApplication()panggilan mengembalikan daftar semua aplikasi yang diinstal. Menambahkan bendera tertentu memungkinkan untuk mengambil banyak data tambahan. Melakukannya kemungkinan besar akan gagal, jadi disarankan untuk tidak mengambil data tambahan apa pun dan mengambilnya berdasarkan per aplikasi.

Namun panggilan mungkin masih gagal, jadi penting untuk mengelilinginya catchdan dapat mencoba lagi jika perlu.

Sejauh yang saya tahu, tidak ada penyelesaian untuk masalah seperti itu kecuali mencoba kembali dan memastikan untuk mengambil informasi sesedikit mungkin.

3c71
sumber
Terima kasih atas info, buffer itu dibagi di antara semua transaksi dalam aplikasi!
Artem Mostyaev
1
Jika ini masalahnya, mengapa saya hanya menggunakan ponsel Android 4.4 dan tidak ada tempat lain. Saya pikir ini lebih merupakan bug di 4.4 yang saya tidak tahu mengapa.
JPM
9

Saya juga mendapat pengecualian ini pada Samsung S3. Saya mencurigai 2 akar penyebab,

  1. Anda memiliki bitmap yang memuat dan mengambil terlalu banyak memori, gunakan perampingan
  2. Anda memiliki beberapa drawable yang hilang dari folder drawable-_dpi, Android mencari mereka dalam drawable, dan mengubah ukurannya, membuat setContentView Anda tiba-tiba melompat dan menggunakan banyak memori.

Gunakan DDMS dan lihat tumpukan Anda saat Anda memainkan aplikasi Anda, yang akan memberi Anda beberapa indikasi di mana setcontentview membuat masalah.

Saya menyalin semua drawables di semua folder untuk menghilangkan masalah 2.

Masalah teratasi.

Siddharth
sumber
Pengecualian memori / bitmap biasanya terlihat berbeda. Saya sudah melihat banyak dari mereka menguji dengan Android 2.x - 4.x dan pengecualian selalu terlihat berbeda. Tapi, siapa tahu, mungkin ini juga terkait tetapi khusus untuk versi 4.x.
Ixx
10
Ini hanya pengecualian yang mengerikan, sehubungan dengan informasi, karena tidak memberikan petunjuk tentang dari mana masalah itu berasal.
Ixx
Saya pikir beberapa hari sudah berakhir, apa temuan Anda?
Denny
8

Tambahkan ini ke Aktivitas Anda

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

Ini bekerja untuk saya, berharap juga akan membantu Anda

Makvin
sumber
7
Saya pikir, itu adalah petunjuk yang paling berbahaya. Mengapa kita harus menghapus data yang ingin kita pulihkan onCreate()?
CoolMind
2
Implikasi dari kode ini adalah Anda akhirnya TIDAK menyelamatkan keadaan instance Anda ...
Justin
4

Jadi bagi kami, kami mencoba mengirim objek yang terlalu besar melalui antarmuka AIDL kami ke layanan jarak jauh. Ukuran transaksi tidak boleh melebihi 1MB. Permintaan dipecah menjadi potongan-potongan terpisah 512KB dan dikirim satu per satu melalui antarmuka. Solusi brutal yang saya tahu tapi hei - Android :(

Kevin Parker
sumber
4

Anda telah menghapus InstanceState lama Anda dari metode onSaveInstanceState , dan itu akan berfungsi dengan baik. Saya menggunakan FragmentStatePagerAdapter untuk viewpager saya jadi saya tetap di bawah metode Override ke dalam aktivitas orang tua saya untuk menghapus InstanceState.

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

Saya menemukan solusi ini dari sini android.os.TransactionTooLargeException di Nougat

varotariya vajsi
sumber
Terima kasih banyak.
Andrain
Terima kasih jawaban Anda, bantu saya
Jatin Patel
3

Baru-baru ini saya juga menemukan kasus yang menarik saat bekerja dengan Penyedia Kontak Android .

Saya perlu memuat foto-foto kontak dari basis data kontak internal dan menurut arsitektur sistem, semua data ini dikirim melalui permintaan ke Penyedia Kontak.

Karena berfungsi sebagai aplikasi terpisah - semua jenis transfer data dilakukan dengan menggunakan mekanisme Binder dan buffer Binder ikut bermain di sini.

Kesalahan utama saya adalah bahwa saya tidak menutup dengan Cursordengan data gumpalan diperoleh dari Kontak Provider, sehingga memori yang dialokasikan untuk penyedia meningkat dan ini menggelembungkan Binder penyangga sampai aku punya banyak !!!FAILED BINDER TRANSACTION!!!pesan dalam output LogCat saya.

Jadi ide utamanya adalah bahwa ketika Anda bekerja dengan Penyedia Konten eksternal dan mendapatkan Cursordari mereka, selalu tutup ketika Anda selesai bekerja dengan mereka.

Alex Bonel
sumber
3

Saya menghadapi masalah yang sama ketika saya mencoba mengirim bitmap melalui Intent dan pada saat yang sama ketika saya melipat aplikasi.

Bagaimana itu dijelaskan dalam artikel ini, masukkan uraian tautan di sini hal itu terjadi ketika suatu Aktivitas sedang dalam proses berhenti, itu berarti bahwa Aktivitas itu mencoba mengirim Bundel keadaan tersimpannya ke sistem OS untuk menjaga keamanan untuk pemulihan nanti (setelah perubahan konfigurasi atau memproses kematian) tetapi satu atau lebih dari Bundel yang dikirimnya terlalu besar.

Saya menyelesaikannya melalui retasan dengan menimpa onSaveInstanceState di Aktivitas saya:

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

dan super call comment. Ini adalah hack kotor tetapi bekerja dengan sempurna. Bitmap berhasil dikirim tanpa crash. Semoga ini bisa membantu seseorang.

Anonim
sumber
2

Dalam kasus saya, saya mendapatkan TransactionTooLargeException sebagai kerusakan sekunder setelah pustaka asli macet dengan SIGSEGV. Kerusakan pustaka asli tidak dilaporkan sehingga saya hanya menerima TransactionTooLargeException.

chris
sumber
2

Saya mendapatkan ini di syncadapter saya ketika mencoba untuk massalMasukkan ContentValues ​​yang besar []. Saya memutuskan untuk memperbaikinya sebagai berikut:

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));
}
Pepijn
sumber
2
Bagaimana jika yang lain gagal? Anda perlu melakukan lebih banyak pembagian, menggunakan loop. Apakah mungkin ada cara untuk mendapatkan ukuran transaksi dan mendapatkan ukuran transaksi maksimal?
pengembang android
2

Bagi saya itu juga FragmentStatePagerAdapter, namun mengesampingkan saveState()tidak berhasil. Begini cara saya memperbaikinya:

Saat memanggil FragmentStatePagerAdapterkonstruktor, simpan daftar fragmen terpisah di dalam kelas, dan tambahkan metode untuk menghapus fragmen:

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

Kemudian di Activity, simpan ViewPagerposisi dan panggil adapter.removeFragments()dengan onSaveInstanceState()metode yang diganti :

private int pagerPosition;

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

Terakhir, pada onResume()metode yang diganti , instantiate ulang adaptor jika tidak null. (Jika itu null, maka Activitysedang dibuka untuk pertama kalinya atau setelah aplikasi telah dimatikan oleh Android, di mana onCreateakan melakukan pembuatan adaptor.)

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

Pastikan Anda tidak memasukkan data objek Intent berukuran besar. Dalam kasus saya, saya menambahkan ukuran String 500k dan kemudian memulai aktivitas lain. Selalu gagal dengan pengecualian ini. Saya menghindari berbagi data antara aktivitas dengan menggunakan variabel aktivitas statis - Anda tidak harus mengirimnya ke Intent dan kemudian menariknya.

Apa yang saya miliki:

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);
Gladimdim
sumber
Ini ide yang sangat buruk. Menggunakan variabel statis dengan cara itu adalah bau kode. Juga, coba jalankan kode ini dengan tanda "Jangan simpan aktivitas" dan tekan home setelah Anda menavigasi ke PageWebView. Setelah Anda membuka kembali aktivitas Anda, Anda mungkin akan mendapatkan crash karena MainActivity akan mati 100% dengan semua variabelnya.
Kyrylo Zapylaiev
1

Ketika saya berurusan dengan WebViewaplikasi saya, itu terjadi. Saya pikir ini terkait dengan addViewsumber daya UI. Dalam aplikasi saya, saya menambahkan beberapa kode WebViewActivityseperti ini di bawah ini kemudian berjalan ok:

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

Saya menemukan akar penyebab ini (kami mendapat keduanya "menambahkan jendela gagal" dan file descriptor bocor seperti kata mvds).

Ada sebuah bug di BitmapFactory.decodeFileDescriptor()Android 4.4. Ini hanya terjadi ketika inPurgeabledan inInputShareabledari BitmapOptionsdiatur ke true. Ini menyebabkan banyak masalah di banyak tempat berinteraksi dengan file.

Perhatikan bahwa metode ini juga dipanggil dari MediaStore.Images.Thumbnails.getThumbnail().

Universal Image Loader dipengaruhi oleh masalah ini. Picasso dan Glide tampaknya tidak terpengaruh. https://github.com/nostra13/Android-Universal-Image-Loader/issues/1020

ya
sumber
1

Satu baris kode ini dalam metode writeToParcel (Parcel dest, int flags) membantu saya untuk menyingkirkan TransactionTooLargeException.

dest=Parcel.obtain(); 

Setelah kode ini hanya saya menulis semua data ke objek paket yaitu dest.writeInt () dll.

dilip
sumber
1

Cobalah menggunakan EventBusatau ContentProvidermenyukai solusi.

Jika Anda berada dalam proses yang sama (biasanya semua aktivitas Anda akan), coba gunakan EventBus, karena dalam proses pertukaran data TIDAK perlu buffer, sehingga Anda tidak perlu khawatir tentang data Anda terlalu besar. (Anda bisa menggunakan metode panggilan untuk mengirimkan data, dan EventBus menyembunyikan hal-hal buruk) Berikut adalah detailnya:

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

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

Jika kedua sisi Intent tidak dalam proses yang sama, coba agak ContentProvider.


Lihat TransactionTooLargeException

Transaksi Binder gagal karena terlalu besar.

Selama panggilan prosedur jarak jauh, argumen dan nilai balik panggilan ditransfer sebagai objek Parcel yang disimpan dalam buffer transaksi Binder. Jika argumen atau nilai pengembalian terlalu besar untuk muat dalam buffer transaksi, maka panggilan akan gagal dan TransactionTooLargeException akan dibuang.

boileryao
sumber
1

Saya mendapat TransactionTooLargeException dari kesalahan Stackoverflow dalam tes Android Espresso. Saya menemukan jejak tumpukan kesalahan stackoverflow di log ketika saya melepas filter Logcat untuk aplikasi saya.

Saya menduga bahwa Espresso menyebabkan TransactionTooLargeException ketika mencoba menangani stacktrace pengecualian yang sangat besar.

Dagmar
sumber
1

Satu dapat menggunakan:

android:largeHeap="true"

di Android Manifest di bawah tag aplikasi.

Ini menyelesaikan masalah dalam kasus saya!

MazRoid
sumber
Dalam kasus saya (karena memanggil onSaveInstantStatekegiatan / fragmen dan menyimpan daftar besar) itu tidak membantu.
CoolMind
1
Ini dianggap sebagai praktik buruk karena Anda tidak berurusan dengan alasan mengapa ada banyak data yang disimpan. Pada perangkat yang lebih baru, aplikasi crash dan batasnya jauh lebih kecil (256KB). Selidiki mengapa Anda menyimpan banyak dulu dan menguranginya.
Tim Kist
1

Saya juga menghadapi masalah ini untuk data Bitmap yang berpindah dari satu aktivitas ke aktivitas lain, tetapi saya membuat solusi dengan menjadikan data saya sebagai data statis dan ini berfungsi sempurna untuk saya

Dalam kegiatan pertama:

public static Bitmap bitmap_image;

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

dan dalam aktivitas kedua:

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

Ini terjadi di aplikasi saya karena saya meneruskan daftar hasil pencarian dalam argumen fragmen, menugaskan daftar itu ke properti fragmen - yang sebenarnya merupakan referensi ke lokasi yang sama dalam memori yang ditunjukkan oleh argumen fragmen - kemudian menambahkan item baru ke daftar, yang juga mengubah ukuran argumen fragmen. Ketika aktivitas ditangguhkan, kelas fragmen dasar mencoba untuk menyimpan argumen fragmen di onSaveInstanceState, yang mogok jika argumen lebih besar dari 1MB. Sebagai contoh:

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

Solusi termudah dalam hal ini adalah menetapkan salinan daftar ke properti fragmen alih-alih menetapkan referensi:

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

Solusi yang lebih baik lagi adalah tidak membagikan begitu banyak data dalam argumen.

Saya mungkin tidak akan pernah menemukan ini tanpa bantuan jawaban ini dan TooLargeTool .

McLarge Besar
sumber
1

Saya juga menjalankan TransactionTooLargeException. Pertama saya telah berusaha memahami di mana itu terjadi. Saya tahu alasan mengapa hal itu terjadi. Setiap dari kita tahu karena kontennya yang besar. Masalah saya seperti itu dan saya menyelesaikannya. Mungkin solusi ini bisa bermanfaat bagi siapa saja. Saya memiliki aplikasi yang mendapatkan konten dari api. Saya mendapatkan hasil dari API di layar pertama dan mengirimkannya ke layar kedua. Saya dapat mengirim konten ini ke layar kedua dengan sukses. Setelah layar kedua jika saya ingin pergi layar ketiga pengecualian ini terjadi. Setiap layar saya dibuat dari Fragment. Saya perhatikan ketika saya pergi dari layar kedua. Ini menyimpan konten bundelnya. jika konten ini terlalu besar pengecualian ini terjadi. Solusi saya adalah setelah saya mendapatkan konten dari bundel saya menghapusnya.

class SecondFragment : BaseFragment() {

    lateinit var myContent: MyContent

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        myContent = arguments?.getParcelable("mycontent")
        arguments?.clear()
    }
nebyan
sumber
Meskipun ini benar (memalukan bagi saya, saya memahami hal yang sama setelah satu tahun), bagaimana fragmen akan lakukan jika itu dibuat ulang (rotasi layar)?
CoolMind
0

Sebuah solusi akan untuk aplikasi untuk menulis ArrayList (atau objek apa pun yang menyebabkan masalah) ke sistem file, kemudian meneruskan referensi ke file itu (misalnya, nama file / jalur) melalui Intent to the IntentService dan kemudian membiarkan IntentService mengambil konten file dan mengubahnya kembali ke ArrayList.

Ketika IntentService telah selesai dengan file, itu harus menghapusnya atau meneruskan instruksi kembali ke aplikasi melalui Siaran Lokal untuk menghapus file yang dibuatnya (dengan mengembalikan referensi file yang sama dengan yang dipasok ke sana).

Untuk info lebih lanjut lihat jawaban saya untuk masalah terkait ini .

larangan geoengineering
sumber
0

Sebagai Maksud, Penyedia Konten, Messenger, semua layanan sistem seperti Telepon, Vibrator dll. Memanfaatkan penyedia infrastruktur IPC oleh Binder. Selain itu callback daur hidup aktivitas juga menggunakan infrastruktur ini.

1MB adalah batas keseluruhan pada semua transaksi binder yang dieksekusi dalam sistem pada saat tertentu.

Jika ada banyak transaksi yang terjadi ketika niat dikirim, mungkin gagal meskipun data tambahan tidak besar. http://codetheory.in/an-overview-of-android-binder-framework/

Shinoo Goyal
sumber
0

Dengan begitu banyak tempat di mana TransactionTooLargeException dapat terjadi - inilah satu lagi yang baru untuk Android 8 - macet ketika seseorang baru mulai mengetik ke dalam EditText jika kontennya terlalu besar.

Ini terkait dengan AutoFillManager (baru di API 26) dan kode berikut di StartSessionLocked():

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

Jika saya mengerti benar, ini memanggil layanan isi-otomatis - melewati AutofillManagerClient di dalam binder. Dan ketika EditText memiliki banyak konten, tampaknya menyebabkan TTLE.

Beberapa hal dapat mengurangi (atau tetap melakukan seperti yang saya uji): Tambahkan android:importantForAutofill="noExcludeDescendants"dalam deklarasi tata letak xml EditText. Atau dalam kode:

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

Solusi kedua yang mengerikan dan mengerikan mungkin juga untuk menggantikan performClick()dan onWindowFocusChanged()metode untuk menangkap kesalahan dalam subkelas TextEdit itu sendiri. Tapi saya pikir itu tidak bijaksana ...

Fattire
sumber