我使用的是LiveData的版本"androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha05"。一旦我的 LiveData 块成功执行,我想显式触发它再次执行,例如
- 我导航到片段
- 用户的数据加载
- 我在同一片段中单击删除 btn
- 用户的数据应刷新
我有一个片段,我观察我的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
公开mediatorLiveData
并observe()
相同,在删除用户时调用refresh()
,其余部分应按原样工作。