Saya mendapatkan laporan pengguna dari aplikasi saya di pasar, memberikan pengecualian berikut:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1109)
at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:399)
at android.app.Activity.onBackPressed(Activity.java:2066)
at android.app.Activity.onKeyUp(Activity.java:2044)
at android.view.KeyEvent.dispatch(KeyEvent.java:2529)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.widget.TabHost.dispatchKeyEvent(TabHost.java:297)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2880)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2853)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2028)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4028)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
at dalvik.system.NativeStart.main(Native Method)
Rupanya itu ada hubungannya dengan FragmentManager, yang tidak saya gunakan. Stacktrace tidak menunjukkan kelas saya sendiri, jadi saya tidak tahu di mana pengecualian ini terjadi dan bagaimana cara mencegahnya.
Sebagai catatan: Saya memiliki tabhost, dan di setiap tab ada ActivityGroup yang beralih di antara Aktivitas.
android
android-fragments
android-viewpager
illegalstateexception
fragmenttransaction
nhaarman
sumber
sumber
FragmentManager
, Honeycomb tentu saja. Apakah ini terjadi pada tablet Honeycomb asli? Atau mungkinkah seseorang menjalankan Honeycomb yang diretas di telepon atau sesuatu dan edisi yang diretas itu mengalami kesulitan?Jawaban:
Silakan periksa jawaban saya di sini . Pada dasarnya saya hanya harus:
Jangan membuat panggilan ke
super()
padasaveInstanceState
metode. Ini mengacaukan segalanya ...Ini yang diketahui bug yang dalam paket dukungan.
Jika Anda perlu menyimpan instance dan menambahkan sesuatu ke
outState
Bundle
Anda dapat menggunakan yang berikut ini:Pada akhirnya solusi yang tepat adalah (seperti yang terlihat di komentar) untuk menggunakan:
saat menambahkan atau melakukan
FragmentTransaction
yang menyebabkanException
.sumber
popBackStackImmediate
segera gagal jika negara telah disimpan. Sebelumnya menambahkan fragmen dengancommitAllowingStateLoss
tidak memainkan peran apa pun. Pengujian saya menunjukkan ini benar. Ini tidak berpengaruh pada pengecualian khusus ini. Yang kita butuhkan adalah sebuahpopBackStackImmediateAllowingStateLoss
metode.Ada banyak masalah terkait dengan pesan kesalahan yang serupa. Periksa baris kedua dari jejak tumpukan khusus ini. Pengecualian ini secara khusus terkait dengan panggilan ke
FragmentManagerImpl.popBackStackImmediate
.Panggilan metode ini, seperti
popBackStack
, akan selalu gagalIllegalStateException
jika status sesi sudah disimpan. Periksa sumbernya. Tidak ada yang bisa Anda lakukan untuk menghentikan pengecualian ini.super.onSaveInstanceState
tidak akan membantu.commitAllowingStateLoss
tidak akan membantu.Inilah cara saya mengamati masalahnya:
onSaveInstanceState
dipanggil.popBackStackImmediate
dicoba.IllegalStateException
terlempar.Inilah yang saya lakukan untuk menyelesaikannya:
Karena tidak mungkin untuk menghindari
IllegalStateException
panggilan balik, tangkap & abaikan saja.Ini cukup untuk menghentikan aplikasi agar tidak mogok. Tetapi sekarang pengguna akan memulihkan aplikasi dan melihat bahwa tombol yang mereka pikir telah mereka tekan belum ditekan sama sekali (menurut mereka). Fragmen formulir masih menunjukkan!
Untuk memperbaiki ini, ketika dialog dibuat, buat beberapa negara untuk menunjukkan proses telah dimulai.
Dan simpan status ini dalam bundel.
Jangan lupa untuk memuatnya kembali
onViewCreated
Kemudian, ketika melanjutkan, kembalikan fragmen-fragmen jika kirim sebelumnya dicoba. Ini mencegah pengguna untuk kembali ke formulir yang tampaknya tidak terkirim.
sumber
popBackStackImmediate
itu disebut oleh Android itu sendiri?Periksa apakah aktivitas
isFinishing()
sebelum menunjukkan fragmen dan perhatikancommitAllowingStateLoss()
.Contoh:
sumber
DialogFragment
. Lihat stackoverflow.com/questions/15729138/… untuk solusi bagus lainnya, stackoverflow.com/a/41813953/2914140 membantu saya.Ini Oktober 2017, dan Google membuat Perpustakaan Dukungan Android dengan hal-hal baru yang disebut komponen Siklus Hidup. Ini memberikan beberapa ide baru untuk masalah 'Tidak dapat melakukan tindakan ini setelah onSaveInstanceState'.
Pendeknya:
Versi lebih panjang dengan jelaskan:
mengapa masalah ini muncul?
Itu karena Anda mencoba menggunakan
FragmentManager
dari aktivitas Anda (yang akan menyimpan fragmen Anda, saya kira?) Untuk melakukan transaksi untuk fragmen Anda. Biasanya ini akan terlihat seperti Anda mencoba melakukan transaksi untuk fragmen yang akan datang, sementara aktivitas host sudah memanggilsavedInstanceState
metode (pengguna mungkin kebetulan menyentuh tombol beranda sehingga aktivitas memanggilonStop()
, dalam kasus saya itu alasannya)Biasanya masalah ini seharusnya tidak terjadi - kami selalu mencoba memuat fragmen ke dalam aktivitas di awal, seperti
onCreate()
metode adalah tempat yang sempurna untuk ini. Tetapi kadang-kadang ini bisa terjadi , terutama ketika Anda tidak dapat memutuskan fragmen apa yang akan Anda muat ke aktivitas itu, atau Anda mencoba memuat fragmen dariAsyncTask
blok (atau apa pun akan memakan waktu sedikit). Waktu, sebelum transaksi fragmen benar-benar terjadi, tetapi setelah metode aktivitasonCreate()
, pengguna dapat melakukan apa saja. Jika pengguna menekan tombol beranda, yang memicu metode aktivitasonSavedInstanceState()
, akan adacan not perform this action
crash.Jika ada yang ingin melihat lebih dalam tentang masalah ini, saya sarankan mereka untuk melihat posting blog ini . Itu terlihat jauh di dalam lapisan kode sumber dan menjelaskan banyak tentang hal itu. Selain itu, ini memberikan alasan bahwa Anda tidak boleh menggunakan
commitAllowingStateLoss()
metode ini untuk menyelesaikan masalah ini (percayalah itu tidak menawarkan apa pun yang baik untuk kode Anda)Bagaimana cara memperbaikinya?
Haruskah saya menggunakan
commitAllowingStateLoss()
metode untuk memuat fragmen? Tidak seharusnya Anda tidak ;Haruskah saya mengganti
onSaveInstanceState
metode, abaikansuper
metode di dalamnya? Tidak seharusnya Anda tidak ;Haruskah saya menggunakan
isFinishing
aktivitas dalam magis , untuk memeriksa apakah aktivitas host pada saat yang tepat untuk transaksi fragmen? Ya ini sepertinya cara yang tepat untuk dilakukan.Lihatlah apa yang dapat dilakukan komponen Siklus Hidup .
Pada dasarnya, Google membuat beberapa implementasi di dalam
AppCompatActivity
kelas (dan beberapa kelas dasar lainnya yang harus Anda gunakan dalam proyek Anda), yang membuatnya lebih mudah untuk menentukan status siklus hidup saat ini . Lihatlah kembali masalah kita: mengapa masalah ini terjadi? Itu karena kita melakukan sesuatu pada waktu yang salah. Jadi kami berusaha untuk tidak melakukannya, dan masalah ini akan hilang.Saya sedikit memberi kode untuk proyek saya sendiri, ini yang saya lakukan
LifeCycle
. Saya kode di Kotlin.Seperti yang saya tunjukkan di atas. Saya akan memeriksa status siklus aktivitas host. Dengan komponen Siklus Hidup dalam pustaka dukungan, ini bisa lebih spesifik. Kode tersebut
lifecyclecurrentState.isAtLeast(Lifecycle.State.RESUMED)
berarti, jika keadaan saat ini setidaknyaonResume
, tidak lebih lama dari itu? Yang memastikan metode saya tidak akan dieksekusi selama beberapa kondisi kehidupan lainnya (sepertionStop
).Apakah semuanya sudah selesai?
Tentu saja tidak. Kode yang saya tunjukkan memberi tahu beberapa cara baru untuk mencegah aplikasi mogok. Tetapi jika itu pergi ke keadaan
onStop
, baris kode itu tidak akan melakukan hal-hal dan dengan demikian tidak menunjukkan apa pun di layar Anda. Ketika pengguna kembali ke aplikasi, mereka akan melihat layar kosong, itulah aktivitas host kosong yang tidak menunjukkan fragmen sama sekali. Ini pengalaman buruk (yeah sedikit lebih baik daripada crash).Jadi di sini saya berharap mungkin ada sesuatu yang lebih baik: aplikasi tidak akan crash jika datang ke keadaan hidup lebih lambat daripada
onResume
, metode transaksi sadar keadaan kehidupan; selain itu, aktivitas akan mencoba melanjutkan untuk menyelesaikan tindakan transaksi fragmen, setelah pengguna kembali ke aplikasi kami.Saya menambahkan sesuatu ke metode ini:
Saya menyimpan daftar di dalam
dispatcher
kelas ini , untuk menyimpan fragmen itu tidak memiliki kesempatan untuk menyelesaikan tindakan transaksi. Dan ketika pengguna kembali dari layar beranda dan menemukan masih ada fragmen yang menunggu untuk diluncurkan, itu akan pergi keresume()
metode di bawah@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
anotasi. Sekarang saya pikir itu harus berfungsi seperti yang saya harapkan.sumber
FragmentDispatcher
menggunakan daftar untuk menyimpan fragmen yang tertunda jika hanya akan ada satu fragmen yang dipulihkan?Berikut adalah solusi berbeda untuk masalah ini.
Menggunakan variabel anggota pribadi Anda dapat mengatur data yang dikembalikan sebagai maksud yang kemudian dapat diproses setelah super.onResume ();
Seperti itu:
sumber
super.onActivityResult()
.Solusi singkat dan bekerja:
Ikuti Langkah Sederhana
Langkah
Langkah 1: Override
onSaveInstanceState
state di masing-masing fragmen. Dan hapus metode super dari itu.Langkah 2: Gunakan
fragmentTransaction.commitAllowingStateLoss( );
bukannya
fragmentTransaction.commit( );
operasi fragmen sementara.sumber
WASPADALAH , menggunakan
transaction.commitAllowingStateLoss()
bisa berakibat pengalaman buruk bagi pengguna. Untuk informasi lebih lanjut tentang mengapa pengecualian ini dilemparkan, lihat posting ini .sumber
Saya menemukan solusi kotor untuk masalah seperti ini. Jika Anda masih ingin menyimpannya
ActivityGroups
untuk alasan apa pun (saya punya alasan pembatasan waktu), Anda tinggal menerapkandi Anda
Activity
dan lakukan beberapaback
kode di sana. bahkan jika tidak ada Metode seperti itu di Perangkat lama, Metode ini dipanggil oleh yang lebih baru.sumber
Jangan gunakan commitAllowingStateLoss (), seharusnya hanya digunakan untuk kasus-kasus di mana tidak apa-apa bagi negara UI untuk mengubah tiba-tiba pada pengguna.
https://developer.android.com/reference/android/app/FragmentTransaction.html#commitAllowingStateLoss ()
Jika transaksi terjadi di ChildFragmentManager dari parentFragment, gunakan parentFragment.isResume () luar untuk memeriksa.
sumber
Saya punya masalah yang sama, skenarionya seperti ini:
The onCreate metode dari kegiatan seperti ini:
Pengecualian dilemparkan karena ketika konfigurasi berubah (perangkat diputar), aktivitas dibuat, fragmen utama diambil dari riwayat manajer fragmen dan pada saat yang sama fragmen sudah memiliki referensi TUA ke aktivitas yang dihancurkan.
mengubah implementasi untuk memecahkan masalah ini:
Anda perlu mengatur pendengar Anda setiap kali aktivitas dibuat untuk menghindari situasi di mana fragmen-fragmen tersebut memiliki referensi untuk contoh-contoh aktivitas yang lama hancur.
sumber
Jika Anda mewarisi dari
FragmentActivity
, Anda harus memanggil superclass dionActivityResult()
:Jika Anda tidak melakukan ini dan mencoba menampilkan kotak dialog fragmen dalam metode itu, Anda bisa mendapatkan OP
IllegalStateException
. (Sejujurnya, saya tidak begitu mengerti mengapa panggilan super memperbaiki masalah.onActivityResult()
Disebut sebelumnyaonResume()
, jadi seharusnya masih tidak diizinkan untuk menampilkan kotak dialog fragmen.)sumber
Saya mendapatkan pengecualian ini ketika saya menekan tombol kembali untuk membatalkan pemilih pemilih pada aktivitas fragmen peta saya. Saya menyelesaikan ini dengan mengganti kode onResume (di mana saya menginisialisasi fragmen) untuk mulai () dan aplikasi bekerja dengan baik. Semoga membantu.
sumber
Saya pikir menggunakan
transaction.commitAllowingStateLoss();
bukanlah solusi terbaik. Pengecualian ini akan dibuang ketika konfigurasi aktivitas berubah dan terpecah-pecahonSavedInstanceState()
dipanggil dan kemudian metode panggilan balik async Anda mencoba melakukan fragmen.Solusi sederhana dapat memeriksa apakah aktivitas mengubah konfigurasi atau tidak
mis. periksa
isChangingConfigurations()
yaitu
if(!isChangingConfigurations()) { //commit transaction. }
Lihat tautan ini juga
sumber
Mungkin solusi paling halus dan paling sederhana yang saya temukan dalam kasus saya adalah untuk menghindari mengeluarkan fragmen yang menyinggung dari tumpukan sebagai respons terhadap hasil aktivitas. Jadi mengubah panggilan ini di
onActivityResult()
:untuk ini:
membantu dalam kasus saya.
sumber
Jika Anda melakukan beberapa FragmentTransaction di onActivityResult apa yang dapat Anda lakukan, Anda dapat menetapkan beberapa nilai boolean di dalam onActivityResult kemudian di onResume Anda dapat melakukan Transaksi FragmentTransaction Anda berdasarkan nilai boolean. Silakan merujuk kode di bawah ini.
sumber
Courtesy: Solusi untuk IllegalStateException
Masalah ini telah mengganggu saya untuk banyak waktu tetapi untungnya saya datang dengan solusi konkret untuk itu. Penjelasan rinci tentang hal itu ada di sini .
Menggunakan commitAllowStateloss () dapat mencegah pengecualian ini tetapi akan menyebabkan penyimpangan UI. Sejauh ini kami telah memahami bahwa IllegalStateException ditemui ketika kami mencoba untuk melakukan fragmen setelah keadaan Aktivitas hilang - jadi kami hanya harus menunda transaksi sampai keadaan dipulihkan . Ini bisa dilakukan seperti ini
Deklarasikan dua variabel boolean pribadi
Sekarang di onPostResume () dan onPause kita mengatur dan menghapus variabel boolean kita adalahTransactionSafe. Ide adalah untuk menandai transaksi aman hanya ketika aktivitas berada di latar depan sehingga tidak ada kemungkinan stateloss.
-Apa yang telah kami lakukan sejauh ini akan menghemat dari IllegalStateException tetapi transaksi kami akan hilang jika mereka dilakukan setelah aktivitas bergerak ke latar belakang, seperti commitAllowStateloss (). Untuk membantu dengan itu kita memiliki variabel boolean isTransactionPending
sumber
Transaksi fragmen tidak boleh dieksekusi setelah
Activity.onStop()
! Pastikan Anda tidak memiliki panggilan balik apa pun yang dapat melakukan transaksi setelahnyaonStop()
. Lebih baik untuk memperbaiki alasan daripada mencoba untuk mengatasi masalah dengan pendekatan seperti.commitAllowingStateLoss()
sumber
Mulai dari pustaka dukungan versi 24.0.0 Anda dapat memanggil
FragmentTransaction.commitNow()
metode yang melakukan transaksi ini secara sinkron alih-alih panggilancommit()
diikuti olehexecutePendingTransactions()
. Seperti dokumentasi mengatakan pendekatan ini lebih baik:sumber
Setiap kali Anda mencoba memuat fragmen dalam aktivitas Anda, pastikan bahwa aktivitas sedang dalam resume dan tidak akan berhenti sementara. Dalam keadaan jeda, Anda mungkin akhirnya kehilangan operasi komit yang dilakukan.
Anda dapat menggunakan transaction.commitAllowingStateLoss () alih-alih transaction.commit () untuk memuat fragmen
atau
Buat boolean dan periksa apakah aktivitas tidak akan berhenti
lalu saat memuat cek fragmen
sumber
Untuk menghindari masalah ini, kita dapat menggunakan Komponen Arsitektur Navigasi , yang diperkenalkan di Google I / O 2018. Komponen Arsitektur Navigasi menyederhanakan implementasi navigasi di aplikasi Android.
sumber
Sehubungan dengan jawaban bagus @Anthonyeef, berikut adalah contoh kode di Jawa:
sumber
Jika Anda mengalami crash dengan metode popBackStack () atau popBackStackImmediate (), silakan coba perbaiki dengan:
Ini bekerja untuk saya juga.
sumber
Dalam kasus saya, saya mendapatkan kesalahan ini dalam metode override bernama onActivityResult. Setelah menggali saya baru tahu mungkin saya perlu memanggil ' super ' sebelumnya.
Saya menambahkannya dan berhasil
Mungkin Anda hanya perlu menambahkan 'super' pada setiap override yang Anda lakukan sebelum kode Anda.
sumber
Ekstensi Kotlin
Pemakaian:
sumber
fragment: Fragment
? Ya, saya mencoba varian ini, tetapi dalam kasus ini sebuah fragmen akan dibuat dalam semua kasus (bahkan ketika fragmentManager == null, tetapi saya tidak menemukan situasi ini). Saya memperbarui jawabannya dan mengubah nol untuk memberi tagaddToBackStack()
.Kecelakaan ini disebabkan oleh transaksi FragmentTransaction yang dilakukan setelah siklus hidup pemiliknya telah berjalan diSaveInstanceState. Ini sering disebabkan oleh melakukan FragmentTransactions dari panggilan balik asinkron. Lihat sumber daya yang ditautkan untuk lebih jelasnya.
Transaksi Fragmen & Aktivitas Kehilangan Negara
http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html
sumber
Tambahkan ini dalam aktivitas Anda
sumber
Saya juga mengalami masalah ini dan masalah terjadi setiap kali ketika konteks Anda
FragmentActivity
berubah (mis. Orientasi layar diubah, dll.). Jadi perbaikan terbaik untuk itu adalah memperbarui konteks dari blog AndaFragmentActivity
.sumber
Saya berakhir dengan membuat fragmen basis dan membuat semua fragmen di aplikasi saya memperluasnya
Lalu ketika saya mencoba menunjukkan sebuah fragmen, saya menggunakan
showAllowingStateLoss
sebagai gantinyashow
seperti ini:
Saya menemukan solusi ini dari PR ini: https://github.com/googlesamples/easypermissions/pull/170/files
sumber
Solusi lain yang mungkin, yang saya tidak yakin jika membantu dalam semua kasus (asal di sini ):
sumber
Saya tahu ada jawaban yang diterima oleh @Ovidiu Latcu tetapi setelah beberapa saat, kesalahan masih berlanjut.
Crashlytics masih mengirim saya pesan kesalahan aneh ini.
Namun kesalahan sekarang hanya terjadi pada versi 7+ (Nougat) Perbaikan saya adalah menggunakan commitAllowingStateLoss () alih-alih komit () di fragmentTransaction.
Posting ini ini bermanfaat untuk commitAllowingStateLoss () dan tidak pernah punya masalah fragmen lagi.
Singkatnya, jawaban yang diterima di sini mungkin bekerja pada versi Android pra Nougat.
Ini mungkin menghemat seseorang beberapa jam mencari. kode senang <3 sorakan
sumber