[go: nahoru, domu]

Fix ConcurrentModificationException on the OnDestinationChangedListener

Go back to using the CopyOnWriteArrayList to ensure that
modifying the list of OnDestinationChangedListeners is safe.

RelNote: "You will no longer get a ConcurrentModificationException when
using OnDestinationChangedListeners."
Test: NavControllerTest
Bug: 188860458

Change-Id: Ib17074c773ed9462c6a69ad384c23e28fa8abaf6
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
index 71e4e6f..d3f9e3a 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
@@ -1956,6 +1956,27 @@
         assertThat(backPressedIntercepted).isTrue()
     }
 
+    @UiThreadTest
+    @Test
+    fun testOnDestinationChangedListenerConcurrentModification() {
+        val navController = createNavController()
+        navController.setGraph(R.navigation.nav_simple)
+
+        val listener = object : NavController.OnDestinationChangedListener {
+            override fun onDestinationChanged(
+                controller: NavController,
+                destination: NavDestination,
+                arguments: Bundle?
+            ) {
+                navController.removeOnDestinationChangedListener(this)
+            }
+        }
+
+        navController.addOnDestinationChangedListener(listener)
+        navController.addOnDestinationChangedListener { _, _, _ -> }
+        navController.navigate(R.id.second_test)
+    }
+
     @Test
     fun createGraph() {
         val graph = navController.createGraph(startDestination = DESTINATION_ID) {
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
index 009d740..e8209a6 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
+++ b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
@@ -43,6 +43,7 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.asSharedFlow
+import java.util.concurrent.CopyOnWriteArrayList
 
 /**
  * NavController manages app navigation within a [NavHost].
@@ -104,8 +105,7 @@
     private val backStackStates = mutableMapOf<String, ArrayDeque<NavBackStackEntryState>>()
     private var lifecycleOwner: LifecycleOwner? = null
     private var viewModel: NavControllerViewModel? = null
-    private val >
-        mutableListOf<OnDestinationChangedListener>()
+    private val >
 
     private val lifecycleObserver: LifecycleObserver = LifecycleEventObserver { _, event ->
         if (_graph != null) {