TL; DR अपने navigate
कॉल को try-catch
(सरल तरीके से) लपेटें , या सुनिश्चित करें कि navigate
कम समय में केवल एक कॉल होगी । यह समस्या संभवतः दूर नहीं होगी। अपने ऐप में बड़ा कोड स्निपेट कॉपी करें और आज़माएं।
हैलो। उपरोक्त कुछ उपयोगी प्रतिक्रियाओं के आधार पर, मैं अपना समाधान साझा करना चाहूंगा जिसे बढ़ाया जा सकता है।
यहाँ कोड है कि मेरे आवेदन में इस दुर्घटना का कारण है:
@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);
}
बग को आसानी से पुन: पेश करने का एक तरीका उन आइटमों की सूची पर कई उंगलियों के साथ टैप करना है जहां प्रत्येक आइटम पर क्लिक नई स्क्रीन में नेविगेशन में हल होता है (मूल रूप से लोग जो नोट करते हैं - बहुत कम समय में दो या अधिक क्लिक। )। मैंने गौर किया:
- पहला
navigate
आह्वान हमेशा ठीक काम करता है;
- का दूसरा और सभी चालान
navigate
विधि के हल होते हैं IllegalArgumentException
।
मेरे दृष्टिकोण से, यह स्थिति बहुत बार दिखाई दे सकती है। चूँकि कोड को दोहराना एक बुरा अभ्यास है और यह हमेशा अच्छा होता है कि मैं इसके प्रभाव का एक बिंदु अगले समाधान के बारे में सोचूँ:
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.");
}
}
}
और इस प्रकार उपरोक्त कोड केवल एक पंक्ति में इस से बदलता है:
Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);
इसके लिए:
NavigationHandler.navigate(recyclerView, R.id.action_listFragment_to_listItemInfoFragment, bundle);
यह थोड़ा छोटा भी हो गया। कोड का परीक्षण उस सटीक स्थान पर किया गया था जहां दुर्घटना हुई थी। इसे अब और अनुभव नहीं किया है, और आगे की इसी गलती से बचने के लिए अन्य नेविगेशन्स के लिए एक ही समाधान का उपयोग करेंगे।
किसी भी विचार का स्वागत है!
क्या वास्तव में दुर्घटना का कारण बनता है
याद रखें कि जब हम विधि का उपयोग करते हैं तो हम उसी नेविगेशन ग्राफ, नेविगेशन नियंत्रक और बैक-स्टैक के साथ काम करते हैं Navigation.findNavController
।
हमें हमेशा एक ही नियंत्रक और ग्राफ मिलता है। जब navigate(R.id.my_next_destination)
ग्राफ कहा जाता है और बैक-स्टैक लगभग तुरंत बदल जाता है जबकि यूआई अभी तक अपडेट नहीं किया गया है। बस जल्दी नहीं है, लेकिन यह ठीक है। बैक-स्टैक को बदलने के बाद नेविगेशन सिस्टम को दूसरी navigate(R.id.my_next_destination)
कॉल मिलती है । चूंकि बैक-स्टैक बदल गया है इसलिए अब हम स्टैक में शीर्ष टुकड़े के सापेक्ष काम करते हैं। शीर्ष टुकड़ा वह टुकड़ा है जिसका उपयोग करके आप नेविगेट करते हैं R.id.my_next_destination
, लेकिन इसमें ID के साथ आगे कोई गंतव्य नहीं है R.id.my_next_destination
। इस प्रकार आप प्राप्त करते हैंIllegalArgumentException
आईडी के कारण कि टुकड़ा के बारे में कुछ भी नहीं पता है।
यह सटीक त्रुटि NavController.java
विधि में पाई जा सकती है findDestination
।