我正在使用LiveData的版本“ androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha05”。一旦LiveData块成功执行,我想明确触发它再次执行,例如
我有一个片段,可以观察我的LiveData,一个带有LiveData和存储库的ViewModel:
ViewModel:
fun getUserLiveData() = liveData(Dispatchers.IO) { val userData = usersRepo.getUser(userId) emit(userData) }
片段:
viewModel.getUserLiveData(viewLifecycleOwner, androidx.lifecycle.Observer {..
然后我正在尝试实现所需的行为,如下所示:
viewModel.deleteUser() viewModel.getUserLiveData()
如果成功完成LiveData块下面的文档,并且如果我在LiveData块中放入 while(true),那么我的数据将刷新,但是我不刷新希望这样做,因为我需要以被动方式更新视图。
如果[block]成功完成,则或由于[LiveData]以外的原因而被取消 变为非活动状态,即使[LiveData]处于活动状态,它也不会重新执行 非活动周期。
也许我错过了一些东西,我该如何重用相同的LiveDataScope来实现此目标?任何帮助将不胜感激。
答案 0 :(得分:1)
我找到了解决方案。我们可以使用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()
}
}
答案 1 :(得分:0)
您可以创建一个可观察对象,并在viewModel中设置该值,然后在片段中对其进行观察。这是您可以使用的示例:
ViewModel
private val _myObservable = LiveData<*>
val observable : LiveData<*> = _myObservable
fun getUserLiveData(){
val userData = usersRepo.getUser(userId)
_myObservable.value = userData
}
然后在片段中:
viewModel.myObservable.observeNullsafe(owner){
//do anything you want to do with the user value
}
因此,现在无论何时调用getUserData
,它都会将更改发送到myObservable
中,您可以使用它。您不需要自己发射它。
希望有帮助。
答案 2 :(得分:0)
要使用liveData {..}块执行此操作,您需要定义一些命令源,然后在一个块中订阅它们。示例:
tabbrev
您应该问自己一个问题:也许改用普通的MutableLiveData并自己更改其值会容易些吗?
livedata {...}构建器可以很好地工作,因为您可以收集一些数据流(例如,来自Room DB的Flow / Flowable),而对于普通的非流源则不太理想,您需要通过以下方式来请求数据你自己。
答案 3 :(得分:0)
您可以使用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}
}
}
将mediatorLiveData
暴露于您的View
和observe()
上,当您的用户被删除时,请致电refresh()
,其余用户应照常工作。
答案 4 :(得分:0)
首先将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
从userList中删除单个用户并得到通知:
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()
,即可将数据获取到观察者块。
答案 5 :(得分:0)
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块{}中的命令不会再次执行。 好吧,是的,在拥有活动的viewmodel中的观察者被触发了,但是带有旧数据。 没有进一步的网络通话。
悲伤。很伤心与Channel和SwitchMap机制的其他建议相比,“解决方案”似乎很有希望,并且减少了重复性。