Merge "Remember the graph that is passed to a NavHost" into androidx-master-dev
diff --git a/navigation/navigation-compose/build.gradle b/navigation/navigation-compose/build.gradle
index 0f3208c..e8377ac8 100644
--- a/navigation/navigation-compose/build.gradle
+++ b/navigation/navigation-compose/build.gradle
@@ -38,6 +38,7 @@
api project(":compose:ui:ui")
api "androidx.navigation:navigation-runtime-ktx:2.3.1"
+ androidTestImplementation project(":compose:material:material")
androidTestImplementation 'androidx.navigation:navigation-testing:2.3.1'
androidTestImplementation project(path: ':internal-testutils-navigation'), {
exclude group: 'androidx.navigation', module: 'navigation-common-ktx'
diff --git a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
index 9a71f30..a1b852e 100644
--- a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
+++ b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
@@ -17,12 +17,21 @@
package androidx.navigation.compose
import android.net.Uri
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material.Button
+import androidx.compose.material.Text
import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.savedinstancestate.rememberSavedInstanceState
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ContextAmbient
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
import androidx.core.net.toUri
import androidx.navigation.NavGraph
import androidx.navigation.NavHostController
@@ -30,6 +39,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
+import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Rule
import org.junit.Test
@@ -84,6 +94,58 @@
}
@Test
+ fun testNavigateOutsideStateChange() {
+ lateinit var navController: NavHostController
+ val text = "myButton"
+ var counter = 0
+ composeTestRule.setContent {
+ navController = rememberNavController()
+ var state by remember { mutableStateOf(0) }
+ Column(Modifier.fillMaxSize()) {
+ NavHost(navController, startDestination = "first") {
+ composable("first") { }
+ composable("second") { }
+ }
+ Button(
+ >
+ state++
+ counter = state
+ }
+ ) {
+ Text(text)
+ }
+ }
+ }
+
+ assertWithMessage("Destination should be added to the graph")
+ .that("first" in navController.graph)
+ .isTrue()
+
+ composeTestRule.runOnIdle {
+ navController.navigate("second")
+ }
+
+ composeTestRule.runOnIdle {
+ assertWithMessage("second destination should be current")
+ .that(
+ navController.currentDestination?.hasDeepLink(Uri.parse(createRoute("second")))
+ ).isTrue()
+ }
+
+ composeTestRule.onNodeWithText(text)
+ .performClick()
+
+ composeTestRule.runOnIdle {
+ // ensure our click listener was fired
+ assertThat(counter).isEqualTo(1)
+ assertWithMessage("second destination should be current")
+ .that(
+ navController.currentDestination?.hasDeepLink(Uri.parse(createRoute("second")))
+ ).isTrue()
+ }
+ }
+
+ @Test
fun testPop() {
lateinit var navController: TestNavHostController
composeTestRule.setContent {
@@ -113,8 +175,8 @@
lateinit var state: MutableState<String>
composeTestRule.setContent {
state = remember { mutableStateOf("first") }
-
- navController = TestNavHostController(ContextAmbient.current)
+ val context = ContextAmbient.current
+ navController = remember { TestNavHostController(context) }
NavHost(navController, startDestination = state.value) {
test("first")
@@ -127,9 +189,9 @@
}
composeTestRule.runOnIdle {
- assertWithMessage("Second destination should be current")
+ assertWithMessage("First destination should be current")
.that(
- navController.currentDestination?.hasDeepLink(createRoute("second").toUri())
+ navController.currentDestination?.hasDeepLink(createRoute("first").toUri())
).isTrue()
}
}
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
index e86802b..ed00cd4 100644
--- a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
@@ -42,6 +42,9 @@
* Once this is called, any Composable within the given [NavGraphBuilder] can be navigated to from
* the provided [navController].
*
+ * The builder passed into this method is [remember]ed. This means that for this NavHost, the
+ * contents of the builder cannot be changed.
+ *
* @sample androidx.navigation.compose.samples.BasicNav
*
* @param navController the navController for this host
@@ -70,6 +73,9 @@
* Once this is called, any Composable within the given [NavGraphBuilder] can be navigated to from
* the provided [navController].
*
+ * The graph passed into this method is [remember]ed. This means that for this NavHost, the graph
+ * cannot be changed.
+ *
* @param navController the navController for this host
* @param graph the graph for this host
*/
@@ -79,6 +85,7 @@
var context = ContextAmbient.current
val lifecycleOwner = LifecycleOwnerAmbient.current
val viewModelStore = ViewModelStoreOwnerAmbient.current.viewModelStore
+ val rememberedGraph = remember { graph }
// on successful recompose we setup the navController with proper inputs
// after the first time, this will only happen again if one of the inputs changes
@@ -98,8 +105,8 @@
}
}
- onCommit(graph) {
- navController.graph = graph
+ onCommit(rememberedGraph) {
+ navController.graph = rememberedGraph
}
val restorableStateHolder = rememberRestorableStateHolder<UUID>()