Um ViewModel com estado
Hoje, quero compartilhar com você uma variante útil da classe ViewModel que escrevi e que venho usando há algum tempo.
Para gerenciar e expor o estado de um ViewModel , pode-se usar a popular API do Kotlins, StateFlow .
Vamos representar nosso estado de IU com a classe de dados abaixo:
data class UiState(
val isLoading: Boolean = false,
val hasError: Boolean = false,
val data: ScreenData? = null,
)
Para expor o estado acima à interface do usuário, usamos uma classe que estende o ViewModel:
class ScreenViewModel() : ViewModel() {
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
suspend fun fetchData() {
_uiState.update { state ->
state.copy(
isLoading = true,
hasError = false
)
}
val fetchedData = fetchDataFromNetwork()
val failed = fetchedData is Error
val data = fetchedData as? Data
_uiState.update { state ->
state.copy(
isLoading = false,
hasError = failed,
data = data,
)
}
}
}
Vamos supor ainda que precisamos de outra função que atualize os dados, então escreveríamos algo como:
suspend fun updateData(newData: Data) {
_uiState.update { state ->
state.copy(
isLoading = true,
hasError = false
)
}
val update = updateAndGetData(newData)
val failed = update is Error
val data = update as? Data
_uiState.update { state ->
state.copy(
isLoading = false,
hasError = failed,
data = data,
)
}
}
Como muitos de vocês provavelmente já fizeram, usei esse padrão muitas vezes. Então decidi escrever um ViewModel genérico estendido, chamei-o de StatefulViewModel:
open class StatefulViewModel<T>(initState: T): ViewModel() {
private val _uiState = MutableStateFlow(initState)
val uiState = _uiState.asStateFlow()
protected fun updateState(f: T.() -> T) {
_uiState.update(f)
}
protected fun updateState(newState: T) {
_uiState.value = newState
}
protected val state: T
get() = _uiState.value
}
Usando esta nova classe, nosso ScreenViewModel escrito acima pode ser refatorado como abaixo:
class ScreenViewModel : StatefulViewModel<UiState>(UiState()) {
suspend fun fetchData() {
updateState {
copy(isLoading = true, hasError = false)
}
val fetchedData = fetchDataFromNetwork()
val failed = fetchedData is Error
val data = fetchedData as? Data
updateState {
copy(isLoading = false, hasError = failed, data = data)
}
}
suspend fun updateData(newData: Data) {
updateState {
copy(isLoading = true, hasError = false)
}
val update = updateAndGetData()
val failed = update is Error
val data = update as? Data
updateState {
copy(isLoading = false, hasError = failed, data = data)
}
}
}
Espero que você ache a classe StatefulViewModel útil e a use em seu próximo projeto!





































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)