TL; DR Tutup navigate
panggilan Anda dengan try-catch
(cara sederhana), atau pastikan hanya akan ada satu panggilan navigate
dalam waktu singkat. Masalah ini sepertinya tidak akan hilang. Salin cuplikan kode yang lebih besar di aplikasi Anda dan coba.
Halo. Berdasarkan beberapa tanggapan bermanfaat di atas, saya ingin membagikan solusi saya yang dapat diperpanjang.
Berikut adalah kode yang menyebabkan kerusakan ini di aplikasi saya:
@Override
public void onListItemClicked(ListItem item) {
Bundle bundle = new Bundle();
bundle.putParcelable(SomeFragment.LIST_KEY, item);
Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);
}
Cara untuk mereproduksi bug dengan mudah adalah dengan mengetuk dengan banyak jari pada daftar item di mana klik pada setiap item diselesaikan dalam navigasi ke layar baru (pada dasarnya sama dengan yang dicatat orang - dua klik atau lebih dalam waktu yang sangat singkat ). Aku tahu itu:
navigate
Doa pertama selalu bekerja dengan baik;
- Kedua dan semua pemanggilan
navigate
metode lainnya diselesaikan IllegalArgumentException
.
Dari sudut pandang saya, situasi ini mungkin sangat sering muncul. Karena pengulangan kode adalah praktik yang buruk dan selalu baik untuk memiliki satu titik pengaruh, saya memikirkan solusi berikutnya:
public class NavigationHandler {
public static void navigate(View view, @IdRes int destination) {
navigate(view, destination, /* args */null);
}
/**
* Performs a navigation to given destination using {@link androidx.navigation.NavController}
* found via {@param view}. Catches {@link IllegalArgumentException} that may occur due to
* multiple invocations of {@link androidx.navigation.NavController#navigate} in short period of time.
* The navigation must work as intended.
*
* @param view the view to search from
* @param destination destination id
* @param args arguments to pass to the destination
*/
public static void navigate(View view, @IdRes int destination, @Nullable Bundle args) {
try {
Navigation.findNavController(view).navigate(destination, args);
} catch (IllegalArgumentException e) {
Log.e(NavigationHandler.class.getSimpleName(), "Multiple navigation attempts handled.");
}
}
}
Dan dengan demikian kode di atas hanya berubah dalam satu baris dari ini:
Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);
untuk ini:
NavigationHandler.navigate(recyclerView, R.id.action_listFragment_to_listItemInfoFragment, bundle);
Bahkan menjadi sedikit lebih pendek. Kode tersebut diuji di tempat yang tepat di mana kerusakan terjadi. Tidak mengalaminya lagi, dan akan menggunakan solusi yang sama untuk navigasi lain untuk menghindari kesalahan yang sama lebih jauh.
Semua pikiran diterima!
Apa sebenarnya penyebab kecelakaan itu
Ingatlah bahwa di sini kita bekerja dengan grafik navigasi, pengontrol navigasi dan back-stack yang sama ketika kita menggunakan metode Navigation.findNavController
.
Kami selalu mendapatkan pengontrol dan grafik yang sama di sini. When navigate(R.id.my_next_destination)
dipanggil graph dan back-stack berubah hampir seketika sementara UI belum diperbarui. Hanya saja tidak cukup cepat, tapi tidak apa-apa. Setelah back-stack berubah, sistem navigasi menerima navigate(R.id.my_next_destination)
panggilan kedua . Karena back-stack telah berubah, kami sekarang beroperasi relatif terhadap fragmen teratas dalam tumpukan. Fragmen teratas adalah fragmen yang Anda R.id.my_next_destination
tuju dengan menggunakan , tetapi tidak berisi tujuan selanjutnya dengan ID R.id.my_next_destination
. Jadi, Anda mendapatkan IllegalArgumentException
karena ID yang tidak diketahui oleh fragmen.
Kesalahan persis ini dapat ditemukan dalam NavController.java
metode findDestination
.