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)
ใดที่เรียกว่ากราฟและแบ็กสแต็กจะเปลี่ยนแปลงเกือบจะทันทีในขณะที่ UI ยังไม่อัปเดต ไม่เร็วพอ แต่ก็โอเค หลังจาก back-stack เปลี่ยนระบบนำทางจะรับnavigate(R.id.my_next_destination)
สายที่สอง เนื่องจาก back-stack มีการเปลี่ยนแปลงตอนนี้เราจึงทำงานโดยสัมพันธ์กับส่วนบนสุดในสแต็ก ส่วนด้านบนเป็นส่วนที่คุณนำทางไปโดยใช้R.id.my_next_destination
แต่มันไม่ได้มีสถานที่ท่องเที่ยวต่อไปเพิ่มเติมใด ๆ ที่มี R.id.my_next_destination
ID ดังนั้นคุณจะได้รับIllegalArgumentException
เนื่องจาก ID ที่ส่วนที่ไม่รู้อะไรเลย
ข้อผิดพลาดนี้แน่นอนสามารถพบได้ในวิธีการNavController.java
findDestination