В проекте реализовано взаимодействие Fragment/Activity и ViewModel через State модель. Все изменения внутри Fragment/Activity делаются через эту модель.
Ипспользуется подход с подписками на 2 LiveData внутри ViewModel.
- Подписка на
eventsQueue- используется для обработки событийных изменений на экране, которые не требуют сохранения состояния. Отображение ошибок вSnackbar, навигация. - Подписка на
state- используется для обработки измененийStateмодели.
В проекте есть несколько базовых классов для удобной работы со State внутри ViewModel.
SingleStateViewModel<T>- используется для экранов которые использую однуStateмодель и все изменения состояния экрана происходят в рамках этой модели. В качестве типа дляSingleStateViewModel<T>передаетсяStateмодель. Для обновленияstateиспользуются методыupdateState.
Пример:
data class ScreenState(val title: String, val subtitle: String)class ScreenViewModel(private val storage: Storage) : SingleStateViewModel<ScreenState>() {
override fun getInitialState(): ScreenState {
return ScreenState(title = "", subtitle = "")//Создаем первичный State экрана
}
/*Обновление отдельных полей state*/
fun loadDataSample() {
val title = storage.getTitle()
val subtitle = storage.getSubtitle()
updateState {
copy(title = title, subtitle = subtitle)
}
}
/*Обновление всего state*/
fun additionalLoadDataSample() {
val title = storage.getTitle()
val subtitle = storage.getSubtitle()
val newState = ScreenState(title, subtitle)
updateState(newState)
}
}MultipleStateViewModel<T>- Используется для экранов где важно переключение состояний (конечный автомат) и не может быть одновременного отображение загрузки и данных. В качестве переключаемых состояний используется LoadingState. В качествеTиспользуется тип данных для отображения, или жеStateкласс экрана. Работа с этим типомViewModelмаксимально похожа на работу сSingleStateViewModel<T>за исключением некоторых дополнительных методов используемых для упрощения изменений State.
Пример:
class ScreenViewModel(
private val userRepository: UserRepository
) : MultipleStateViewModel<User>() {
fun loadDataSample() {
userRepository.getUser()
.schedulersIoToMain()
.doOnSubscribe { showLoading() } //Переключаемся на состояние загрузки
.subscribe(
{ user ->
showContent(user)//Переключаемся на отображение контента
},
{
showStub(it.localizedMessage)//Переключаемся на состояние ошибки
}
)
.autoDispose()
}
}
BaseViewModel- ViewModel в которой реализованы базовые методы работы сeventsQueueи освобождения Rx подписок. Использовать если первые 2 типа ViewModel не подходят.