Step #2: Emitting View States
Then, replace getItems()
in RosterMotor
with:
val states = repo.items()
.map { RosterViewState(it) }
.stateIn(viewModelScope, SharingStarted.Eagerly, RosterViewState())
Flow
has a map()
operator for converting data between types. Here, we map()
the list of ToDoModel
objects into a RosterViewState
.
We then use an stateIn()
extension function. This converts a Flow
into a StateFlow
, ready to be consumed by our RosterListFragment
.
StateFlow
in the "Opting Into SharedFlow and StateFlow" chapter of Elements of Kotlin Coroutines!
A StateFlow
is a flow of states. It holds onto a current state and gives that to any new observer once it starts observing. And, it emits new states to current observers if it is handed a new state.
stateIn()
takes three parameters:
- A
CoroutineScope
(more on this below) - A value indicating when states should start flowing — in this case, we start immediately
- The initial state for the flow — in this case, one with an empty list
For the CoroutineScope
, we use viewModelScope
. viewModelScope
is an extension function supplied by lifecycle-viewmodel-ktx
, to give us a CoroutineScope
associated with our ViewModel
. The major feature of viewModelScope
is that it is aware of the viewmodel’s lifecycle. When the viewmodel is cleared (after the user exits the fragment), any outstanding coroutines being run in the context of the viewModelScope
get canceled.
We use a property (states
), rather than a function. For the view-state pattern, it works best if you have a stable stream of states. That will make our viewmodels a bit more complicated in the future, but it means that our fragments are simpler: just subscribe to the one source of view-states and use them. In fact, we will do just that in the next step.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.