【发布时间】:2021-05-11 06:46:18
【问题描述】:
TL;DR
对于一次又一次添加/删除的片段实例,其 ViewModel 中的viewModelScope 仅在第一次弹出片段之前有效。此后,viewModelScope 变为非活动状态。当我重新添加片段时,如何重新初始化viewModelScope?还是我应该寻找更好的实现来保持它的活跃?
场景:
我在一个旧项目中使用RxJava 到ViewModel 从网络中检索数据,并将更新发送到 UI,我使用了 LiveData。
以下是我在片段中初始化典型 ViewModel 的方式:
private val fruitsViewModel by viewModels<FruitsViewModel>()
下面是上面提到的ViewModel:
class FruitsViewModel: ViewModel {
private var category: String = FruitCategories.DEFAULT
private val _fruits = MutableLiveData<List<Fruit>>()
fun fruits(): LiveData<List<Fruit>> = _fruits
fun updateCategory(newCategory: String) {
this.category = newCategory
fetchFruits()
}
fun fetchFruits() { ... }
}
在 Fragment 的onViewCreated() 中,我调用了fruitsViewModel.fetchFruits()。这很好用(没有任何明显的问题)。
今天,我使用协程切换了 RxJava 特定代码,以在我的 ViewModel 中检索网络数据。像这样的:
fun fetchFruits() {
/* this.fruitsJob = */
viewModelScope.launch {
...
}
}
这也很好用,即使我替换了一个片段并返回它。但是,如果我保留在 Activity 中声明的片段实例,并再次使用它,viewModelScope.launch {} 将不再起作用。像这样的:
class FruitsActivity: AppCompatActivity() {
private val fruitsFragment = FruitsFragment()
private fun showFruitsFragment() {
supportFragmentManager
.beginTransaction()
.replace(getFragmentContainerId(), fruitsFragment)
.addToBackStack(fruitsFragment.tag)
.commit()
}
private fun removeFragments() {
val manager = supportFragmentManager
if (manager.backStackEntryCount > 0) {
val first: FragmentManager.BackStackEntry = manager.getBackStackEntryAt(0)
manager.popBackStack(first.id, FragmentManager.POP_BACK_STACK_INCLUSIVE)
}
}
}
保留片段实例的原因是只加载一次 API 数据,之后,它应该只是在单击按钮时出现,没有任何闪烁/加载。
在我调用removeFragments() 之后,fruitsViewModel 已经调用了它的onCleared() 以保留 fruitsFragment 的声明。因此,它的viewModelScope 变为非活动状态,如果我通过调用showFruitsFragment() 再次添加fruitsFragment,这将不再检索网络数据。这不是我的 Rxjava 实现的情况,因为我没有使用 viewModelScope。
我想我可以通过将fruitsViewModel 链接到FruitsActivity 的实例来解决这个问题。但是,我想知道这是否可以被认为是最好的方法。
【问题讨论】:
-
The reason for keeping the fragment instance is to load API data only once所以听起来你需要一个共享视图模型,不是吗?为什么不将视图模型附加到 Activity 并让它根据需要进行服务调用 -
同意@a_local_nobody 。由于无论附加和分离多少次,您都可以使片段保持更长的时间(类似于 Activity 的生命周期),因此最好使用 Activity 的范围或 Activity 的视图模型。
-
顺便说一句,由于您希望独立于片段的生命周期保留加载的数据,因此数据应该存储在活动而不是片段中。 IMO,保留片段实例不是一个好习惯。
标签: android android-fragments kotlin-coroutines android-viewmodel