Skip to content

Commit dffae20

Browse files
Treehugger RobotGerrit Code Review
authored andcommitted
Merge "Make setOnBackPressedDispatcher idempotent" into androidx-main
2 parents 13bf2b2 + b0af29c commit dffae20

File tree

2 files changed

+54
-3
lines changed

2 files changed

+54
-3
lines changed

navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,52 @@ class NavControllerTest {
311311
assertThat(replacementLifecycleOwner.observerCount).isEqualTo(1)
312312
}
313313

314+
@UiThreadTest
315+
@Test
316+
fun testSetSameOnBackPressedDispatcher() {
317+
val navController = createNavController()
318+
val lifecycleOwner = TestLifecycleOwner(Lifecycle.State.RESUMED)
319+
navController.setLifecycleOwner(lifecycleOwner)
320+
// Set the graph and navigate to another destination to build up our back stack
321+
navController.setGraph(R.navigation.nav_simple)
322+
navController.navigate(R.id.second_test)
323+
324+
val dispatcher = OnBackPressedDispatcher()
325+
navController.setOnBackPressedDispatcher(dispatcher)
326+
assertThat(dispatcher.hasEnabledCallbacks()).isTrue()
327+
// One observer is the NavController itself, the other is the OnBackPressedCallback
328+
assertThat(lifecycleOwner.observerCount).isEqualTo(2)
329+
330+
navController.setOnBackPressedDispatcher(dispatcher)
331+
assertThat(dispatcher.hasEnabledCallbacks()).isTrue()
332+
// One observer is the NavController itself, the other is the OnBackPressedCallback
333+
assertThat(lifecycleOwner.observerCount).isEqualTo(2)
334+
}
335+
336+
@UiThreadTest
337+
@Test
338+
fun testSetNewOnBackPressedDispatcher() {
339+
val navController = createNavController()
340+
val lifecycleOwner = TestLifecycleOwner(Lifecycle.State.RESUMED)
341+
navController.setLifecycleOwner(lifecycleOwner)
342+
// Set the graph and navigate to another destination to build up our back stack
343+
navController.setGraph(R.navigation.nav_simple)
344+
navController.navigate(R.id.second_test)
345+
346+
val dispatcher = OnBackPressedDispatcher()
347+
navController.setOnBackPressedDispatcher(dispatcher)
348+
assertThat(dispatcher.hasEnabledCallbacks()).isTrue()
349+
// One observer is the NavController itself, the other is the OnBackPressedCallback
350+
assertThat(lifecycleOwner.observerCount).isEqualTo(2)
351+
352+
val replacementDispatcher = OnBackPressedDispatcher()
353+
navController.setOnBackPressedDispatcher(replacementDispatcher)
354+
assertThat(replacementDispatcher.hasEnabledCallbacks()).isTrue()
355+
assertThat(dispatcher.hasEnabledCallbacks()).isFalse()
356+
// One observer is the NavController itself, the other is the new OnBackPressedCallback
357+
assertThat(lifecycleOwner.observerCount).isEqualTo(2)
358+
}
359+
314360
@UiThreadTest
315361
@Test
316362
fun testNavigate() {

navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ public open class NavController(
105105
private val backStackMap = mutableMapOf<Int, String?>()
106106
private val backStackStates = mutableMapOf<String, ArrayDeque<NavBackStackEntryState>>()
107107
private var lifecycleOwner: LifecycleOwner? = null
108+
private var onBackPressedDispatcher: OnBackPressedDispatcher? = null
108109
private var viewModel: NavControllerViewModel? = null
109110
private val onDestinationChangedListeners = CopyOnWriteArrayList<OnDestinationChangedListener>()
110111

@@ -1883,17 +1884,21 @@ public open class NavController(
18831884
/** @suppress */
18841885
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
18851886
public open fun setOnBackPressedDispatcher(dispatcher: OnBackPressedDispatcher) {
1886-
checkNotNull(lifecycleOwner) {
1887+
if (dispatcher == onBackPressedDispatcher) {
1888+
return
1889+
}
1890+
val lifecycleOwner = checkNotNull(lifecycleOwner) {
18871891
"You must call setLifecycleOwner() before calling setOnBackPressedDispatcher()"
18881892
}
18891893
// Remove the callback from any previous dispatcher
18901894
onBackPressedCallback.remove()
18911895
// Then add it to the new dispatcher
1892-
dispatcher.addCallback(lifecycleOwner!!, onBackPressedCallback)
1896+
onBackPressedDispatcher = dispatcher
1897+
dispatcher.addCallback(lifecycleOwner, onBackPressedCallback)
18931898

18941899
// Make sure that listener for updating the NavBackStackEntry lifecycles comes after
18951900
// the dispatcher
1896-
lifecycleOwner!!.lifecycle.apply {
1901+
lifecycleOwner.lifecycle.apply {
18971902
removeObserver(lifecycleObserver)
18981903
addObserver(lifecycleObserver)
18991904
}

0 commit comments

Comments
 (0)