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")