While testing my app I realized that if a user pressed the FloatingActionButton
quickly, several times, the onClick call back could be fired multiple times. In my case, this caused the backstack being popped multiple times, as the onPopBackStack
callback bubbles up to the NavHost
where it has access to the navController
and ivokes the popBackStack
method.
fun AddEditTodoScreen(onPopBackStack: () -> Unit, viewModel: AddEditTodoViewModel = viewModel()) {
var isNavigating by remember{
mutableStateOf(false)
}
LaunchedEffect(key1 = true){
viewModel.uiEvent.collect{event : UiEvent ->
when(event){
is UiEvent.PopBackStack -> onPopBackStack
else -> Unit
}
}
}
Scaffold(floatingActionButton = {
FloatingActionButton(onClick = {
if(!isNavigating){
isNavigating = !isNavigating
onPopBackStack()
}
}) {
Icon(imageVector = Icons.Default.Check, contentDescription = "Check")
}
Currently I'm just setting a isNavigating
to true when the FloatingActionButton
is first clicked and if clicked again, it checks if the isNavigating
flag is set to true, if so it does nothing. What would be a better way, if any, to address this?
Navigation already tells you if you're navigating to a new destination: the Lifecycle
of the NavBackStackEntry
is synchronously changed when you call navigate
, moving you down from the RESUMED
state.
Therefore if you want to avoid handling clicks after you've already started navigating to another screen, you'd want to check the LocalLifecycleOwner
's state:
// This corresponds with the NavBackStackEntry
// associated with this screen
val lifecycleOwner = LocalLifecycleOwner.current
FloatingActionButton(onClick = {
// Get the current state of the Lifecycle
val currentState = lifecycleOwner.lifecycle.currentState
// And ignore click events when you've started navigating
// to another screen
if (currentState.isAtLeast(Lifecycle.State.RESUMED)) {
onPopBackStack()
}
}
As of Lifecycle 2.8.0, the dropUnlessResumed
API does this with just a single line of code:
FloatingActionButton(onClick = dropUnlessResumed {
onPopBackStack()
}