3

I implemented ViewModel driven navigation as shown in my code below. Basic idea is a Singleton class NavigationManager which is available to both, composables and the ViewModel, via dependency injection. The NavigationManager has a SharedFlow property named direction which can be changed from e.g. the ViewModel and is observed by the composables.

Now my question on this: Is it safe to use a SharedFlow in this situation? As a SharedFlow is a hot flow and therefore can emit events while not being observed, is it possible that navigation events are lost? E.g. is it possible that a navigation event is emitted while the user rotates his phone and the NavigationManger.direction SharedFlow isn't observed for a short time (as the activity is recreated on rotation)?

// MainActivity.kt
// navigationManager.direction is observed here
// NavigationManager is a Singleton injected via dependency injection
@AndroidEntryPoint
class MainActivity : ComponentActivity() {

    @Inject
    lateinit var navigationManager: NavigationManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyJetpackComposeTheme {
                val navController = rememberNavController()

                MyNavHost(navController)

                LaunchedEffect(navigationManager.direction) {
                    navigationManager.direction.collect { direction ->
                        direction?.let {
                            Log.i("NavTest", "change route to: $direction")
                            navController.navigate(direction)
                        }
                    }
                }
            }
        }
    }
}

// The navigation manager. Instantiating it is done by the
// depdendency injection framework, not shown here for brevitiy
class NavigationManager(private val externalScope: CoroutineScope) {
    private val _direction = MutableSharedFlow<String?>()
    val direction : SharedFlow<String?> = _direction

    fun navigate(direction: String) {
        Log.d("NavTest", "navigating to $direction")

        externalScope.launch {
            _direction.emit(direction)
        }
    }
}

// triggering navigation from inside a ViewModel would be like this
// (navigationManger would be injected via dependency injection)
navigationManager.navigate("some_direction")
stefan.at.kotlin
  • 15,347
  • 38
  • 147
  • 270
  • 1
    Yes, I believe it's totally safe, this is the approach I [suggest](https://stackoverflow.com/a/71036376/3585796) for single shot operations such as this case, also you can define it as `MutableSharedFlow` as it doesn't have any default value were you would need to pass `null` – Phil Dukhov Jun 06 '22 at 04:08

0 Answers0