I migrated my app from plain SQLite to use Room in order to make things more robust. Now I have a Flow which queries all my users from the db inside my DAO:
@Query("SELECT * FROM users")
fun getAllAsFlow(): Flow<List<UserData>>
In my repository I am exposing this as:
val allUsersFlow: Flow<List<UserData>> = userDao.getAllAsFlow()
And then in my ViewModel:
val allUsers: Flow<List<UserData>> = repository.allUsersFlow
To finally collect it in a Composable with Lifecyleawareness
val users by usersPageViewModel.allUsers.collectAsStateWithLifecycle(initialValue = listOf())
Now everything works as expected, but when I navigate to another page (with push to stack), and then pop it again, the Composable is recomposed and the users is an empty list before it gets the data again, which results in an empty screen view for a splitsecond.
Now if I replace collectAsStateWithLifecycle
with collectAsState
, this does not happen because the collection is not aware of the first screen going to the background.
So what is the best way to achieve the behaviour of collectAsState
, but still being aware of the apps global lifecycle (e.g. going to background). Can I pass collectAsStateWithLifecycle
the main activities lifecycle somehow?
In your view model, you just need to convert the cold flow from the repository into a hot StateFlow
:
val allUsers: StateFlow<List<UserData>> = repository.allUsersFlow.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = emptyList(),
)
That way your view model always has a value for the flow and can provide it whenever needed.
Since you now provide the initialValue
in the view model, you can drop it from the collectAsStateWithLifecycle
in your composable.