Ami*_*mir 6 android mvvm viewmodel kotlin android-livedata
我正在寻找观察数据的最佳方法ViewModel
。
我正在使用 MVVM + 数据绑定。
存储库:
private val data = MutableLiveData<String>()
suspend fun getData(): LiveData<String> {
return withContext(IO) {
val response = apiRequest { api.getData() }
data.postValue(response)
data
}
}
Run Code Online (Sandbox Code Playgroud)
它从服务器请求数据并返回实时数据。ViewModel必须观察数据的变化。
视图模型:
suspend fun getData() {
val data = repository.getData()
MediatorLiveData<String>().apply {
addSource(data) {
gotData(it)
removeSource(data)
}
observeForever { }
}
}
private fun gotData(data: String) {
//use data
}
Run Code Online (Sandbox Code Playgroud)
ViewModel 使用来观察来自存储库MediatorLiveData
的更改。LiveData
我已将数据添加为源以观察更改并在触发后将其删除,以防止在多次获取数据时多次触发事件。并且必须有一个假观察者来MediatorLiveData
触发 onChange 方法MediatorLiveData
。
假设我只需要数据来隐藏/显示视图(或者甚至将数据填充到我的 recyclerview 的适配器)。然后我只需调用下面的代码并使用 Observable 和 DataBinding,如下所示:
val adapter: ObservableField<DataAdapter> = ObservableField()
val recyclerviewVisibility: ObservableField<Int> = ObservableField(View.GONE)
...
...
recyclerviewVisibility.set(View.VISIBLE)
adapter.set(DataAdapter(dataList))
Run Code Online (Sandbox Code Playgroud)
所以我不需要将数据传递给Fragment
或Activity
使用viewLifecycleOwner
. 我也不能使用observeForever
in ViewModel
,因为在某些情况下它可能会多次触发 onChange 方法。
有没有更好的方法来获取和观察数据ViewModel
?
解决方案 :
我发现实现我的目标的最佳方法是从存储库获取数据而不使用LiveData
:
存储库
suspend fun getData() : String{
return apiRequest { api.getData() }
}
Run Code Online (Sandbox Code Playgroud)
视图模型
suspend fun getData(){
val data = repository.getData()
gotData(data)
}
fun gotData(data: String) {
//use data
}
Run Code Online (Sandbox Code Playgroud)
现在简单多了。
奖金:
扩大:
fun <T : Any> ViewModel.request(request: suspend () -> (T), result: (T) -> (Unit) = {}) {
viewModelScope.launch {
result(request())
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
request({request.getData()}) {
//use data
}
Run Code Online (Sandbox Code Playgroud)
如果我认为问题正确,我认为您可以map
在LiveData
.
也许最好更改存储库代码,如下所示:
private val reload = MutableLiveData<Unit>()
val data: LiveData<String> =
reload.switchMap {
liveData(IO) {
emit(apiRequest { api.getData() })
}
}
fun reload() {
reload.postValue(Unit)
}
Run Code Online (Sandbox Code Playgroud)
然后,在ViewModel
使用地图变换时,您可以拦截发射值:
val data: LiveData<String> =
repository.data.map {
gotData(it)
it
}
fun reload() {
repository.reload()
}
Run Code Online (Sandbox Code Playgroud)
使用此结构,您将能够reload()
在每次需要时调用 ViewModel,从而从 api 获取新数据并将其发送到 ViewModel 的data
.