Search code examples
androidkotlinandroid-jetpack-composeandroid-jetpack-navigationjetpack-compose-accompanist

How to check if a composable is on top of the back stack or not?


I have a navigation graph containing a HomeScreen and a MyBottomSheet. For bottom sheets I am using Accompanist Navigation. Both of the destinations share a common ViewModel which is scoped to that navigation graph. From that ViewModel I am exposing a Flow<MyEvent> where MyEvent is:

sealed interface MyEvent
object MyEvent1: MyEvent
object MyEvent2: MyEvent

The two composables look like this:

@Composable
fun HomeScreen(viewModel: MyViewModel) {
    LaunchedEffect(Unit) {
        viewModel.eventsFlow.collect {
            if(it is Event1) {
                handleEvent1()
            }
        }
    }
    ...
}

@Composable
fun MyBottomSheet(viewModel: MyViewModel) {
    LaunchedEffect(Unit) {
        viewModel.eventsFlow.collect {
            if(it is Event2) {
                handleEvent2()
            }
        }
    }
    ...
}

Note that I want HomeScreen to handle Event1 and MyBottomSheet to handle Event2 (these events are basically navigation events).

The problem is that when MyBottomSheet is visible, both the composables are collecting the flow at the same time because of which Event2 also gets collected by HomeScreen. What I want is that when MyBottomSheet is the topmost destination in back stack, HomeScreen shouldn't be collecting flow. One of the possible solutions in my mind is:

@Composable
fun HomeScreen(viewModel: MyViewModel) {
    LaunchedEffect(isHomeScreenOnTheTopOfBackStack) {
        if(isHomeScreenOnTheTopOfBackStack) {
            viewModel.eventsFlow.collect {
                if(it is Event1) {
                    handleEvent1()
                }
            }
        }
    }
    ...
}

Now here, how can I check if HomeScreen is on top of the back stack or not?

Or is there a better way to approach this problem?


Solution

  • Turned out it was quite easy. We can use navController.currentBackStackEntryAsState() in the nav graph and pass the Boolean to the HomeScreen.

    composable("home") {
        val isOnTop = navController.currentBackStackEntryAsState().value?.destination?.route == "home"
        HomeScreen(
            viewModel = //,
            isHomeScreenOnTheTopOfBackStack = isOnTop
        )
    }