Saya punya masalah besar dengan cara kerja fragmen android backstack dan akan sangat berterima kasih atas bantuan yang ditawarkan.
Bayangkan Anda memiliki 3 Fragmen
[1] [2] [3]
Saya ingin pengguna dapat menavigasi [1] > [2] > [3]
tetapi dalam perjalanan kembali (menekan tombol kembali) [3] > [1]
.
Seperti yang saya bayangkan, ini akan dilakukan dengan tidak memanggil addToBackStack(..)
saat membuat transaksi yang membawa fragmen [2]
ke pemegang fragmen yang ditentukan dalam XML.
Kenyataannya seolah-olah jika saya tidak ingin [2]
muncul lagi ketika pengguna menekan tombol kembali [3]
, saya tidak boleh memanggil addToBackStack
transaksi yang menunjukkan fragmen [3]
. Ini tampaknya benar-benar kontra-intuitif (mungkin berasal dari dunia iOS).
Bagaimanapun jika saya melakukannya dengan cara ini, ketika saya pergi dari [1] > [2]
dan menekan kembali saya tiba kembali [1]
seperti yang diharapkan.
Jika saya pergi [1] > [2] > [3]
dan kemudian menekan kembali saya melompat kembali ke [1]
(seperti yang diharapkan). Sekarang perilaku aneh terjadi ketika saya mencoba dan melompat [2]
lagi dari [1]
. Pertama-tama [3]
ditampilkan secara singkat sebelum [2]
terlihat. Jika saya menekan kembali saat ini [3]
ditampilkan, dan jika saya menekan kembali sekali lagi aplikasi akan keluar.
Adakah yang bisa membantu saya untuk memahami apa yang terjadi di sini?
Dan berikut ini file layout xml untuk aktivitas utama saya:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<fragment
android:id="@+id/headerFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
class="com.fragment_test.FragmentControls" >
<!-- Preview: layout=@layout/details -->
</fragment>
<FrameLayout
android:id="@+id/detailFragment"
android:layout_width="match_parent"
android:layout_height="fill_parent"
/>
Perbarui Ini adalah kode yang saya gunakan untuk membangun oleh nav heirarchy
Fragment frag;
FragmentTransaction transaction;
//Create The first fragment [1], add it to the view, BUT Dont add the transaction to the backstack
frag = new Fragment1();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.commit();
//Create the second [2] fragment, add it to the view and add the transaction that replaces the first fragment to the backstack
frag = new Fragment2();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.addToBackStack(null);
transaction.commit();
//Create third fragment, Dont add this transaction to the backstack, because we dont want to go back to [2]
frag = new Fragment3();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.commit();
//END OF SETUP CODE-------------------------
//NOW:
//Press back once and then issue the following code:
frag = new Fragment2();
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.detailFragment, frag);
transaction.addToBackStack(null);
transaction.commit();
//Now press back again and you end up at fragment [3] not [1]
Terimakasih banyak
sumber
Jawaban:
Penjelasan: apa yang terjadi disini?
Jika kita ingat bahwa
.replace()
itu sama dengan.remove().add()
yang kita ketahui dari dokumentasi:maka yang terjadi adalah seperti ini (saya menambahkan angka ke frag untuk membuatnya lebih jelas):
(di sini semua hal yang menyesatkan mulai terjadi)
Ingatlah bahwa
.addToBackStack()
hanya menyimpan transaksi, bukan fragmen itu sendiri! Jadi sekarang kita memilikifrag3
tata letak:Solusi yang memungkinkan
Pertimbangkan menerapkan
FragmentManager.BackStackChangedListener
untuk memperhatikan perubahan di back-stack dan menerapkan logika Anda dalamonBackStackChanged()
metode:FragmentTransaction.addToBackStack(String name);
sumber
FragmentManager.BackStackChangedListener
untuk mengawasi perubahan pada back-stack. Pantau semua transaksi Anda denganonBackStackChanged()
metode dan bertindak seperlunya: misalnya. melacak hitungan transaksi di BackStack; periksa transaksi tertentu berdasarkan nama (FragmentTransaction addToBackStack (String name)
) dll.Baik!!! setelah banyak mencabut rambut akhirnya saya menemukan cara untuk membuat ini bekerja dengan benar.
Tampaknya fragmen [3] tidak terhapus dari tampilan saat bagian belakang ditekan sehingga Anda harus melakukannya secara manual!
Pertama-tama, jangan gunakan replace () melainkan gunakan hapus dan tambahkan secara terpisah. Sepertinya replace () tidak berfungsi dengan baik.
Bagian selanjutnya adalah mengganti metode onKeyDown dan menghapus fragmen saat ini setiap kali tombol kembali ditekan.
Semoga ini membantu!
sumber
Pertama-tama, terima kasih @Arvis untuk penjelasan yang membuka mata.
Saya lebih suka solusi berbeda daripada jawaban yang diterima di sini untuk masalah ini. Saya tidak suka mengotak-atik perilaku menimpa kembali lebih dari yang benar-benar diperlukan dan ketika saya mencoba menambahkan dan menghapus fragmen sendiri tanpa poping back stack default ketika tombol kembali ditekan saya menemukan diri saya di neraka fragmen :) Jika Anda. tambahkan f2 di atas f1 saat Anda menghapusnya f1 tidak akan memanggil metode callback seperti onResume, onStart, dll. dan itu bisa sangat disayangkan.
Bagaimanapun, inilah cara saya melakukannya:
Saat ini yang dipamerkan hanya fragmen f1.
f1 -> f2
tidak ada yang luar biasa di sini. Kemudian di fragmen f2 kode ini membawa Anda ke fragmen f3.
f2 -> f3
Saya tidak yakin dengan membaca dokumen apakah ini berfungsi, metode transaksi poping ini dikatakan asinkron, dan mungkin cara yang lebih baik adalah memanggil popBackStackImmediate (). Tapi sejauh yang saya tahu di perangkat saya, ini berfungsi dengan sempurna.
Alternatif yang dimaksud adalah:
Di sini sebenarnya akan ada singkat kembali ke f1 beofre pindah ke f3, jadi ada sedikit kesalahan di sana.
Ini sebenarnya yang harus Anda lakukan, tidak perlu menimpa perilaku back-stack ...
sumber
Saya tahu ini pertanyaan lama tetapi saya mendapat masalah yang sama dan memperbaikinya seperti ini:
Pertama, Tambahkan Fragment1 ke BackStack dengan nama (misalnya "Frag1"):
Dan kemudian, Setiap kali Anda ingin kembali ke Fragment1 (bahkan setelah menambahkan 10 fragmen di atasnya), panggil popBackStackImmediate dengan nama:
Semoga ini akan membantu seseorang :)
sumber
Setelah @Arvis membalas saya memutuskan untuk menggali lebih dalam dan saya telah menulis artikel teknologi tentang ini di sini: http://www.andreabaccega.com/blog/2015/08/16/how-to-avoid-fragments-overlapping- karena-ke-backstack-mimpi buruk-di-android /
Untuk pengembang yang malas di sekitar. Solusi saya terdiri dari selalu menambahkan transaksi ke backstack dan melakukan ekstra
FragmentManager.popBackStackImmediate()
saat diperlukan (secara otomatis).Kode ini sangat sedikit baris kode dan, dalam contoh saya, saya ingin melompat dari C ke A tanpa melompat kembali ke "B" jika pengguna tidak masuk lebih dalam di backstack (misal dari C menavigasi ke D).
Karenanya kode yang dilampirkan akan bekerja sebagai berikut A -> B -> C (kembali) -> A & A -> B -> C -> D (kembali) -> C (kembali) -> B (kembali) -> A
dimana
dikeluarkan dari "B" ke "C" seperti dalam pertanyaan.
Ok, Ok ini kodenya :)
sumber
Jika Anda Berjuang dengan addToBackStack () & popBackStack () maka cukup gunakan
Dalam Aktivitas Anda Di OnBackPressed () temukan fargment dengan tag dan kemudian lakukan barang Anda
Untuk Informasi lebih lanjut https://github.com/DattaHujare/NavigationDrawer Saya tidak pernah menggunakan addToBackStack () untuk menangani fragmen.
sumber
Saya pikir, ketika saya membaca cerita Anda, [3] juga ada di belakang. Ini menjelaskan mengapa Anda melihatnya berkedip.
Solusinya adalah tidak pernah mengatur [3] pada stack.
sumber
s old method issue but now it
apa. Terima kasihSaya memiliki masalah serupa di mana saya memiliki 3 fragmen berturut-turut di
Activity
[M1.F0] -> [M1.F1] -> [M1.F2] yang sama diikuti dengan panggilan keActivity
[M2] baru. Jika pengguna menekan tombol di [M2], saya ingin kembali ke [M1, F1] daripada [M1, F2] yang sudah dilakukan oleh perilaku back press.Untuk melakukannya, saya menghapus [M1, F2], panggil acara di [M1, F1], lakukan transaksi, lalu tambahkan [M1, F2] kembali dengan memanggilnya dengan sembunyikan. Ini menghapus pers belakang ekstra yang seharusnya tertinggal.
Hai Setelah melakukan kode ini: Saya tidak dapat melihat nilai Fragment2 saat menekan Tombol Kembali. Kode Saya:
sumber
executePendingTransactions()
,commitNow()
tidak bekerja (Bekerja di androidx (jetpack).
sumber