如何再次调用实时数据协程块



我使用的是LiveData的版本"androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha05"。一旦我的 LiveData 块成功执行,我想显式触发它再次执行,例如

  1. 我导航到片段
  2. 用户的数据加载
  3. 我在同一片段中单击删除 btn
  4. 用户的数据应刷新

我有一个片段,我观察我的LiveData,一个带有LiveData和Repository的ViewModel:

视图模型:

fun getUserLiveData() = liveData(Dispatchers.IO) {
val userData = usersRepo.getUser(userId)
emit(userData) 
}

片段:

viewModel.getUserLiveData.observe(viewLifecycleOwner,
androidx.lifecycle.Observer {.. 

然后我试图实现这样的期望行为:

viewModel.deleteUser()
viewModel.getUserLiveData()

根据下面的文档,LiveData 块不会执行,如果它已成功完成,如果我在 LiveData 块中放置了一段时间(true(,那么我的数据会刷新,但是我不希望这样做,因为我需要被动地更新我的视图。

如果[封禁]成功完成由于[实时数据]以外的原因而被取消 变为非活动状态,即使在 [LiveData] 变为活动状态后也不会重新执行 非活动周期。

也许我错过了一些东西,如何重用相同的LiveDataScope来实现这一点?任何帮助将不胜感激。

要使用 liveData { .. } 块执行此操作,您需要定义一些命令源,然后在块中订阅它们。例:

MyViewModel() : ViewModel() {
val commandsChannel = Channel<Command>()
val liveData = livedata {
commandsChannel.consumeEach { command -> 
// you could have different kind of commands 
//or emit just Unit to notify, that refresh is needed
val newData = getSomeNewData()
emit(newData)
}
}
fun deleteUser() {
.... // delete user
commandsChannel.send(RefreshUsersListCommand)
}
}

你应该问自己的问题:也许使用普通的MutableLiveData会更容易,并自己改变它的值?

livedata { ... } 构建器运行良好,当您可以收集一些数据流(例如来自房间 DB 的 Flow/Flowable(时,对于普通的非流源则不那么好,您需要自己请求数据。

我为此找到了解决方案。我们可以使用switchMap手动调用LiveDataScope

首先,让我们看一下switchMap的官方示例:

/**
* Here is an example class that holds a typed-in name of a user
* `String` (such as from an `EditText`) in a [MutableLiveData] and
* returns a `LiveData` containing a List of `User` objects for users that have
* that name. It populates that `LiveData` by requerying a repository-pattern object
* each time the typed name changes.
* <p>
* This `ViewModel` would permit the observing UI to update "live" as the user ID text
* changes.
**/
class UserViewModel: AndroidViewModel {
val nameQueryLiveData : MutableLiveData<String> = ...
fun usersWithNameLiveData(): LiveData<List<String>> = nameQueryLiveData.switchMap {
name -> myDataSource.usersWithNameLiveData(name)
}
fun setNameQuery(val name: String) {
this.nameQueryLiveData.value = name;
}
}

这个例子非常清楚。我们只需要将nameQueryLiveData更改为您自己的类型,然后将其与LiveDataScope.如:

class UserViewModel: AndroidViewModel {
val _action : MutableLiveData<NetworkAction> = ...
fun usersWithNameLiveData(): LiveData<List<String>> = _action.switchMap {
action -> liveData(Dispatchers.IO){
when (action) {
Init -> {
// first network request or fragment reusing
// check cache or something you saved.
val cache = getCache()
if (cache == null) {
// real fecth data from network
cache = repo.loadData()
}
saveCache(cache)
emit(cache)
}
Reload -> {
val ret = repo.loadData()
saveCache(ret)
emit(ret)
}
}
}
}
// call this in activity, fragment or any view
fun fetchData(ac: NetworkAction) {
this._action.value = ac;
}
sealed class NetworkAction{
object Init:NetworkAction()
object Reload:NetworkAction()
}
}

首先将implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"添加到您的 gradle 文件中。按如下方式ViewModel

MyViewModel() : ViewModel() {
val userList = MutableLiveData<MutableList<User>>()
fun getUserList() {
viewModelScope.launch {
userList.postValue(usersRepo.getUser(userId))
}
}
}

然后服务用户列表:

viewModel.sessionChartData.observe(viewLifecycleOwner, Observer { users ->
// Do whatever you want with "users" data
})

extension从用户列表中删除单个用户并获得通知:

fun <T> MutableLiveData<MutableList<T>>.removeItemAt(index: Int) {
if (!this.value.isNullOrEmpty()) {
val oldValue = this.value
oldValue?.removeAt(index)
this.value = oldValue
} else {
this.value = mutableListOf()
}
}

调用该扩展函数以删除任何用户,删除一个用户后,您将在Observer块中收到通知。

viewModel.userList.removeItemAt(5) // Index 5

当您想从数据源获取userList时,只需调用viewModel.getUserList()您将获得数据到观察者块。

private val usersLiveData = liveData(Dispatchers.IO) {
val retrievedUsers = MyApplication.moodle.getEnrolledUsersCoroutine(course)
repo.users = retrievedUsers
roles.postValue(repo.findRolesByAll())
emit(retrievedUsers)
}
init {
usersMediator.addSource(usersLiveData){ usersMediator.value = it }
}
fun refreshUsers() {
usersMediator.removeSource(usersLiveData)
usersMediator.addSource(usersLiveData) { usersMediator.value = it }

liveData 块 {} 中的命令不会再次执行。 好的,是的,视图模型中的观察者持有活动被触发,但使用旧数据。 不再进行网络调用。

伤心。很伤心。与通道和SwitchMap机制的其他建议相比,"解决方案"似乎很有希望,而且不那么麻烦。

您可以使用MediatorLiveData来实现此目的。

以下是您如何实现这一目标的要点。

class YourViewModel : ViewModel() {
val mediatorLiveData = MediatorLiveData<String>()
private val liveData = liveData<String> {  }
init {
mediatorLiveData.addSource(liveData){mediatorLiveData.value = it}
}
fun refresh() {
mediatorLiveData.removeSource(liveData)
mediatorLiveData.addSource(liveData) {mediatorLiveData.value = it}
}
}

View公开mediatorLiveDataobserve()相同,在删除用户时调用refresh(),其余部分应按原样工作。

最新更新