android - ViewModel 没有分离观察者并导致空指针异常
问题描述
这是我遇到的一个奇怪的错误,我开始认为我的片段的观察者在我弹出那个片段后仍在观察。
所以,我有两个使用相同视图模型的片段,但它们不与活动共享,视图模型实例适用于每个片段
片段B()
private val viewModel by viewModels<OrderViewModel> { VMOrderFactory(
OrderRepoImpl(
OrderDataSource()
)
) }
...
viewModel.fetchOrderStatus(trackingDetails.orderId).observe(viewLifecycleOwner, Observer { result -> ... }
现在,我使用 from FragmentA() Flow 协程在我看来实时保持更新。
订单视图模型
fun fetchOrderStatus(orderId: String) = liveData(Dispatchers.IO){
emit(Resource.Loading())
try{
repo.getOrderStatus(orderId).collect { status ->
emit(status)
}
}catch (e:Exception){
emit(Resource.Failure(e))
}
}
现在是这样的情况
当我在 FragmentA() 中时,它可以工作并获取订单。
现在,如果我FragmentB()
再次返回 FragmentA() 并尝试FragmentA()
使用此视图模型的另一个实例和另一个方法从中删除,则 fetchOrderStatus fromFragmentB()
被执行,并且由于我弹出此片段,它返回一个 nullPointerException
因此,奇怪的是,使用 viewLifeCycleOwner 时,这个观察者在返回 FragmentA() 时并没有与 FragmentB() 分离,而另一个奇怪的事情是,当我迅速从 FragmentB() 回到 FragmentA() 并尝试删除一个订购,但如果我稍等片刻(2 或 3 秒,直到流程附加并请求数据),这将正常工作
可能会发生什么以及我的观察员会发生什么?
片段A()
Fragment A 不使用 FragmentB() 中的 fetchOrderStatus 方法
private val viewModel by viewModels<OrderViewModel> { VMOrderFactory(
OrderRepoImpl(
OrderDataSource()
)
) }
viewModel.deleteOrder(adapter.getItem(position).orderId).observe(viewLifecycleOwner, Observer { result -> ... }
错误在这里抛出,但不是关于 deleteOrder 方法,而是来自 FragmentB() fetchOrderStatus 方法,这很奇怪,因为此时 FragmentB() 被弹出并且它的方法不应该获取任何数据。
也许我需要在弹出这个 fragmentB 时终止流程,但是当它获取并交付时我在 datasource 方法中执行它
awaitClose { subscription.remove() }
解决方案
如果您创建 ViewModel 并提供 Fragment 上下文,则 ViewModel 会在 Fragment 被销毁时被销毁。如果您希望 ViewModel 比片段更长寿,那么您需要使用活动上下文启动它activityViewModel()
推荐阅读
- powershell - Powershell问题比较并将其保存为文本文件
- r - 使用 optim() 进行抛物线插值
- kubernetes - 如何从图像拉取阶段发生错误导致的“待处理”状态中解开 Pod
- python - 按升序对熊猫列进行排序,然后对非 0 重复项进行排序
- peoplesoft - 如何使用单选按钮进行人员编码
- azure - Azure VM 上的 Azure Pipelines 代理
- android - BufferKnife 在构建 gradle Android Studio 时产生问题
- google-cloud-platform - Google Cloud Storage 存储分区中的用户特定对象
- sql - 更新要在同一查询中的列?
- c++ - 为什么类中的组件函数中的 const 是必需的