Andrea
02/23/2022, 11:43 PMdata class HomeUiState(
val users: MutableList<User>
)
class HomeViewModel(
) : ViewModel(){
private val repository: Repository = Repository()
private val viewModelState = MutableStateFlow(HomeUiState(mutableListOf()))
val uiState: StateFlow<HomeUiState> = viewModelState
.stateIn(
viewModelScope,
SharingStarted.Eagerly,
viewModelState.value
)
val userId = MutableStateFlow(1)
// 1 solutions: Keep the list out the UIState and collect it in compose with collectAsState
val userList = userId.flatMapLatest {
repository.getUsersList()
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5000),
emptySet()
)
// 2 solution, flatMapLatest for the filtered list
init {
userId.flatMapLatest {
repository.getUsersList(it)
}.onEach { users ->
viewModelState.update {
it.copy(users = users) }
}.launchIn(viewModelScope)
}
}
Nick Allen
02/24/2022, 12:18 AMstateIn
on a MutableStateFlow
, it is a StateFlow
. If you are worried about callers casting it, you could call .asStateFlow()
.
3. Seems like you want the HomeUiState
so just go with that
4. stateIn
implementation starts a coroutine that collects and updates a MutableStateFlow
so there's really no difference conceptually. Just use stateIn
since it has the code you need already.
You could do this with just one expression:
val uiState: StateFlow<HomeUiState> = userId
.flatMapLatest { repository.getusersList(it) }
.map { HomeUiState(it) }
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5000),
HomeUiState(emptyList())
)
If there's more to HomeUiState
then you can use combine
to build it from multiple `Flow`s.Andrea
02/24/2022, 2:01 AMdata class HomeUiState(
val users: List<User>,
val messages: List<Message>
)
and messages value should be updated in another fun inside the viewmodel using, ad example
fun loadMessages() {
viewModelScope.launch {
// call repository and load someeMessages
viewModelState.update {
it.copy(messages = someeMessages)
}
}
}
I need to keep the private mutableStateFlow to update other properties. I have tried this solution, but maybe there is a better one
val uiState: StateFlow<HomeUiState> = userId.flatMapLatest {
repository.getUsersList(it)
}
.map {
HomeUiState(it, listOf())
}
.combine(viewModelState) { f1, f2 ->
viewModelState.update { it.copy(users = f1.users) }
viewModelState.value
}
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5000),
HomeUiState(listOf(), listOf())
)
Nick Allen
02/24/2022, 2:54 AMcombine(usersFlowexpression, messagesFlowExpression, ::HomeUiState)
.stateIn(…)
When you combine, it gives you the latest from each flow. You can then build the HomeUiState from these latest values.Andrea
02/24/2022, 11:36 PM