Обновление неизменных значений состояния просмотра в Android однонаправленном потоке данных - PullRequest
0 голосов
/ 09 февраля 2020

Вопрос

Я хочу реорганизовать значения неизменяемого состояния просмотра в Android ViewModel (VM), чтобы сделать следующее:

  1. Обновлять состояние просмотра в виртуальной машине без копирования всего состояния просмотра
  2. Сохранять данные состояния просмотра неизменными для просмотра, наблюдающего обновления

Я построил шаблон Android Однонаправленный поток данных (UDF) с использованием LiveData для обновления изменений состояния представления в виртуальной машине, которые наблюдаются в представлении.

См .: Android Однонаправленный поток данных с LiveData - 2.0

Полный пример кода: Открытое приложение Coinverse

Реализация

Существующая реализация использует вложенные LiveData.

  • Одна LiveData val для сохранения состояния просмотра в виртуальной машине
  • Вложенные LiveData для атрибутов состояния просмотра как неизменяемые val s
// Stored as viewState LiveData val in VM
data class FeedViewState(
    val contentList: LiveData<PagedList<Content>>
    val anotherAttribute: LiveData<Int>)

Состояние просмотра создается в виртуальной машине init{...}.

Затем, чтобы обновить состояние просмотра, оно должно быть скопировано и обновлено с заданным атрибутом, поскольку оно является неизменным val. Если атрибут должен быть изменяемым, он может быть переназначен без использования copy в виртуальной машине. Однако быть неизменным важно, чтобы убедиться, что представление не может непреднамеренно изменить val.

class ViewModel: ViewModel() {
    val viewState: LiveData<FeedViewState> get() = _viewState
    private val _viewState = MutableLiveData<FeedViewState>()

    init {
        _viewState.value = FeedViewState(
           contentList = getContentList(...)
           anotherAttribute = ...)
    }

    override fun swipeToRefresh(event: SwipeToRefresh) {
        _viewState.value = _viewState.value?.copy(contentList = getContentList(...))
    }
}

Ответы [ 2 ]

1 голос
/ 10 февраля 2020

Я не уверен, что с «вложенными LiveData» все в порядке. Когда мы работаем с любой реализацией разработки, управляемой событиями (LiveData, RxJava, Flow), мы обычно должны предполагать, что события дискретных данных являются неизменяемыми, а операции над этими событиями являются чисто функциональными. Быть неизменным НЕ является синонимом только для чтения (val). Неизменный означает неизменный. Он должен быть постоянным во времени и работать точно так же при любых обстоятельствах. Это одна из причин, почему мне странно иметь LiveData или ArrayList членов в классе данных, независимо от того, определены они только для чтения или нет.

Другая, техническая причина, по которой следует избегать вложенных потоки: их почти невозможно правильно наблюдать. Каждый раз, когда через внешний поток отправляется новое событие данных, разработчики должны обязательно удалить внутренние подписки, прежде чем наблюдать за новым внутренним потоком, иначе это может вызвать всевозможные проблемы. Какой смысл иметь наблюдателей, осведомленных о жизненном цикле, когда разработчикам нужно вручную отписаться от них?

Почти во всех сценариях ios вложенные потоки могут быть преобразованы в один слой потока. В вашем случае:

class ViewModel: ViewModel() {

    val contentList: LiveData<PagedList<Content>>
    val anotherAttribute: LiveData<Int>

    private val swipeToRefreshTrigger = MutableLiveData<Boolean>(true)

    init {
        contentList = Transformations.switchMap(swipeToRefreshTrigger) {
            getContentList(...)
        }

        anotherAttribute = ...
    }

    override fun swipeToRefresh(event: SwipeToRefresh) {
        swipeToRefreshTrigger.postValue(true)
    }
}

Примечания к PagedList:

PagedList также изменчивы, но я думаю, это то, с чем нам просто нужно жить. PagedList использование - еще одна топика c, поэтому я не буду обсуждать это здесь.

0 голосов
/ 11 февраля 2020

Удалить вложенные LiveData, создать классы состояний.

Подход : сохранение неизменяемого состояния LiveData и эффектов в состоянии представления и классе эффектов представления внутри общедоступной модели представления.

Атрибуты состояния просмотра и эффектов просмотра могут быть значениями LiveData непосредственно в ВМ. Однако я хотел бы организовать состояние представления и эффекты в отдельные классы, чтобы представление могло знать, наблюдает ли оно за состоянием представления или эффектом представления.

class FeedViewState(
        _contentList: MutableLiveData<PagedList<Content>>,
        _anotherAttribute: MutableLiveData<Int>
) {
    val contentList: LiveData<PagedList<Content>> = _contentList
    val anotherAttribute: LiveData<Int> = _anotherAttribute
}

Состояние представления создается в VM.

class ViewModel: ViewModel() {

    val feedViewState: FeedViewState 
    private val _contentList = MutableLiveData<PagedList<Content>>()
    private val _anotherAttribute = MutableLiveData<Int>()

    init {
        feedViewState = FeedViewState(_contentList, _anotherAttribute)
    }

    ...

    fun updateContent(){
        _contentList.value = ...
    }

    fun updateAnotherAttribute(){
        _anotherAttribute.value = ...
    }
}

Тогда атрибуты состояния просмотра будут наблюдаться в активности / фрагменте.

class Fragment: Fragment() {
    private fun observeViewState() {
        feedViewModel.feedViewState.contentList(viewLifecycleOwner){ pagedList: PagedList<Content> ->
            adapter.submitList(pagedList)
        }
        feedViewModel.feedViewState.anotherAttribute(viewLifecycleOwner){ anotherAttribute: Int ->
            //TODO: Do something with other attribute.
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...