Android DialogFragment dismiss后ViewModel销毁致API请求未执行问题咨询
推测合理性判定
你的推测完全合理,问题根因如下:
- 默认情况下你使用的
bonusViewModel是绑定到DialogFragment自身生命周期的,当调用dismiss()后DialogFragment销毁,绑定的ViewModel会触发onCleared()回调 - 如果
submitBonusDecision()内部是通过viewModelScope启动协程执行网络请求,onCleared()触发时viewModelScope会主动取消所有未完成的协程,你代码中调用完提交方法后立刻执行dismiss,大概率会在API请求完成前就触发协程取消,最终导致请求中断。
可行解决方案
你可以根据业务场景选择以下方案,其中支持通过ViewModel实现需求:
方案1:绑定ViewModel到更上层生命周期持有者(推荐,符合ViewModel实现需求)
将bonusViewModel的生命周期绑定到宿主Activity或者父Fragment,而不是当前DialogFragment,这样DialogFragment dismiss销毁时不会影响ViewModel的生命周期,请求可以正常执行完成。
修改ViewModel初始化代码即可:
// 原来的初始化方式(绑定到DialogFragment自身) // val bonusViewModel: BonusViewModel by viewModels() // 修改为绑定到宿主Activity val bonusViewModel: BonusViewModel by activityViewModels() // 如果是在父Fragment中打开的DialogFragment,也可以绑定到父Fragment // val bonusViewModel: BonusViewModel by viewModels(ownerProducer = { requireParentFragment() })
该方案还可以直接通过共享ViewModel将请求结果同步给宿主页面做后续UI更新,比如提交成功后刷新列表。
方案2:延迟dismiss到请求完成后执行
如果你的业务希望用户看到提交结果后再关闭弹窗,可以调整逻辑,不立刻调用dismiss,而是监听API请求的执行结果,拿到成功/失败回调后再执行dismiss,同时可以增加加载态防止用户重复点击:
private fun submitBonusDecision(decision: Boolean) { BONUS_IDENTIFIER.argumentValue()?.let { bonusId -> // 增加加载态,防止重复提交 submitBtn.isEnabled = false loadingPb.visibility = View.VISIBLE bonusViewModel.submitBonusDecision(decision, bonusId) // 监听请求结果 lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { bonusViewModel.submitResultFlow.collect { result -> // 请求完成后再关闭弹窗 dismiss() // 按需提示结果 when(result) { is Result.Success -> Toast.makeText(context, "提交成功", Toast.LENGTH_SHORT).show() is Result.Fail -> Toast.makeText(context, "提交失败:${result.errorMsg}", Toast.LENGTH_SHORT).show() } } } } } }
对应ViewModel中需要新增结果通知的Flow/LiveData:
class BonusViewModel : ViewModel() { private val _submitResultFlow = MutableSharedFlow<Result>() val submitResultFlow = _submitResultFlow.asSharedFlow() fun submitBonusDecision(decision: Boolean, bonusId: String) { viewModelScope.launch { val result = apiService.submitBonus(decision, bonusId) _submitResultFlow.emit(result) } } }
方案3:使用WorkManager执行高优先级请求
如果你的业务要求提交请求必须完成,就算用户关闭APP也不能中断,可以将API请求封装为WorkManager任务,提交任务后立刻dismiss弹窗,系统会保证任务在合适的时机执行完成,不受组件生命周期影响。
内容的提问来源于stack exchange,提问作者Kratos
相关产品推荐
相关产品推荐

