在Android单向数据流中更新不可变视图状态值
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Android单向数据流中更新不可变视图状态值相关的知识,希望对你有一定的参考价值。
问题
我想在Android ViewModel(VM)中重构不可变视图状态的值,以执行以下操作:
- 干净地更新VM中的视图状态,而无需复制整个视图状态
- 保持视图状态数据对视图更新不可变
我使用LiveData构建了android单向数据流(UDF)模式,以更新视图中观察到的VM中的视图状态更改。
参见:Android Unidirectional Data Flow with LiveData — 2.0
完整示例代码:Coinverse Open App
实施
现有实现使用嵌套的LiveData。
- 一个LiveData
val
将视图状态存储在VM中 - 视图状态属性的嵌套LiveData为不可变的
val
s
// Stored as viewState LiveData val in VM
data class FeedViewState(
val contentList: LiveData<PagedList<Content>>
val anotherAttribute: LiveData<Int>)
视图状态在VM的init...
中创建。
然后,为了更新视图状态,必须将其复制并使用给定的属性进行更新,因为它是不可变的val
。如果该属性是可变的,则可以在VM中没有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(...))
尝试的解决方案
Approach:删除视图状态和视图状态属性的LiveData嵌套,同时将视图状态数据保持在单独的类中。
视图状态和视图效果属性可以直接在VM中为LiveData值。但是,我想将视图状态和效果组织到单独的类/对象中,以使视图知道它是观察视图状态还是视图效果。
为了保持视图状态井井有条,我想创建一个非LiveData视图类,其中包含LiveData属性。不幸的是,此模式无法与错误一起编译。
类型为<< [type的表达式'名称'不能作为函数调用。找不到函数invoke()
class FeedViewState2(_contentList: MutableLiveData<PagedList<Content>>,
_anotherAttribute: MutableLiveData<Int>)
val contentList: LiveData<PagedList<Content>> = _contentList
val anotherAttribute: LiveData<Int> = _anotherAttribute
视图状态在VM中创建。
class ViewModel: ViewModel() val feedViewState2: FeedViewState2 private val _contentList = MutableLiveData<PagedList<Content>>() private val _anotherAttribute = MutableLiveData<Int>() init feedViewState2 = FeedViewState2(_contentList, _anotherAttribute)
然后,将在活动/片段中观察视图状态属性。
class Fragment: Fragment() private fun observeViewState() feedViewModel.feedViewState2.contentList(viewLifecycleOwner) pagedList: PagedList<Content> -> adapter.submitList(pagedList) feedViewModel.feedViewState2.anotherAttribute(viewLifecycleOwner) anotherAttribute: Int -> //TODO: Do something with other attribute.
LiveData
,RxJava
,Flow
)时,通常需要假定离散数据事件是不可变的,并且对这些事件的操作是纯功能的。不变是不是只读(val
)的同义词。不可变意味着不可变。它应该是时不变的,并且在任何情况下都应该以完全相同的方式工作。这就是为什么我对在数据类中具有LiveData
或ArrayList
成员感到奇怪的原因之一,无论它们是否被定义为只读。另一个避免嵌套流的技术原因:几乎不可能正确观察它们。每当外部流发出一个新的数据事件时,开发人员必须确保在观察新内部流之前先删除内部订阅,否则可能导致各种问题。当开发人员需要手动取消订阅时,拥有生命周期感知的观察者有什么意义?
几乎在所有情况下,嵌套流都可以转换为一层流。您的情况:
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
的使用是另一个主题,因此在这里我不再讨论。
以上是关于在Android单向数据流中更新不可变视图状态值的主要内容,如果未能解决你的问题,请参考以下文章
我想以不可变的方式更新状态对象,以便react和redux正常工作?