android - 从 Fragment 返回时,Kotlin ViewModel onchange 被多次调用(使用生命周期实现)
问题描述
我正在使用 MVVM 架构。
编码
当我单击一个按钮时,会触发orderAction方法。它只是发布一个枚举(将添加进一步的逻辑)。
视图模型
class DashboardUserViewModel(application: Application) : SessionViewModel(application) {
enum class Action {
QRCODE,
ORDER,
TOILETTE
}
val action: LiveData<Action>
get() = mutableAction
private val mutableAction = MutableLiveData<Action>()
init {
}
fun orderAction() {
viewModelScope.launch(Dispatchers.IO) {
// Some queries before the postValue
mutableAction.postValue(Action.QRCODE)
}
}
}
片段观察 LiveData obj 并调用打开新片段的方法。我在这里使用导航器,但我认为有关它的详细信息在这种情况下没有用处。请注意,我正在使用viewLifecycleOwner
分段
class DashboardFragment : Fragment() {
lateinit var binding: FragmentDashboardBinding
private val viewModel: DashboardUserViewModel by lazy {
ViewModelProvider(this).get(DashboardUserViewModel::class.java)
}
private val observer = Observer<DashboardUserViewModel.Action> {
// Tried but I would like to have a more elegant solution
//if (viewLifecycleOwner.lifecycle.currentState == Lifecycle.State.RESUMED)
it?.let {
when (it) {
DashboardUserViewModel.Action.QRCODE -> navigateToQRScanner()
DashboardUserViewModel.Action.ORDER -> TODO()
DashboardUserViewModel.Action.TOILETTE -> TODO()
}
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentDashboardBinding.inflate(inflater, container, false)
binding.viewModel = viewModel
binding.lifecycleOwner = this
viewModel.action.observe(viewLifecycleOwner, observer)
// Tried but still having the issue
//viewModel.action.reObserve(viewLifecycleOwner, observer)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
// Tried but still having the issue
//viewModel.action.removeObserver(observer)
}
private fun navigateToQRScanner() {
log("START QR SCANNER")
findNavController().navigate(LoginFragmentDirections.actionLoginToPrivacy())
}
}
问题
当我关闭打开的片段(使用 findNavController().navigateUp())时,会立即调用 DashboardFragment 的 Observe.onChanged 并再次打开片段。
我已经检查了这个问题并尝试了上述链接中提出的所有解决方案(如您在注释代码中所见)。只有这个解决方案有效,但它不是很优雅,并迫使我每次都进行检查。
我想尝试一个更可靠和最优的解决方案。
请记住,在该线程中没有生命周期实现。
解决方案
这就是LiveData
工作原理,它是一个价值持有者,它拥有最后一个价值。
如果您需要消耗您的对象,以便该操作仅触发一次,请考虑将您的对象包装在 a 中Consumable
,如下所示
class ConsumableValue<T>(private val data: T) {
private val consumed = AtomicBoolean(false)
fun consume(block: ConsumableValue<T>.(T) -> Unit) {
if (!consumed.getAndSet(true)) {
block(data)
}
}
}
然后您将 LiveData 定义为
val action: LiveData<ConsumableValue<Action>>
get() = mutableAction
private val mutableAction = MutableLiveData<ConsumableValue<Action>>()
然后在你的观察者中,你会做
private val observer = Observer<ConsumableValue<DashboardUserViewModel.Action>> {
it?.consume { action ->
when (action) {
DashboardUserViewModel.Action.QRCODE -> navigateToQRScanner()
DashboardUserViewModel.Action.ORDER -> TODO()
DashboardUserViewModel.Action.TOILETTE -> TODO()
}
}
}
推荐阅读
- react-native - expo-av 裸错误:缺少录音权限
- r - 如何使用 2 个不同的条件将字符串(在一列中)拆分为 2 个单独的列,并且只保留这 2 个列?
- excel - 在 vba 中编辑/更新现有行数据
- python - 将整数字符串列表转换为整数数组的最有效方法
- python - 将 Python 输出管道传输到 NetCat - time.sleep() 会中断输出?
- python - 2列的唯一值不在另一列
- mvvm - MVVM 依赖注入服务使用
- elasticsearch - elasticsearch排序取决于请求命中哪个节点
- python - 访问多级字典的最后一个值
- c# - IdentityServer4 和 UserInfo 端点自定义