Android Kotlin协程报Job was Cancelled导致Spinner为空怎么修复?
根因分析
该偶发问题核心是ShowDatePickerDialog的生命周期和ViewModel、LiveData绑定逻辑错误:
ShowDatePickerDialog本质是DialogFragment,用户选中日期触发onDateSet回调后,Dialog会立即销毁。你在Dialog内部通过ViewModelProvider(this)获取的ViewModel绑定的是当前Dialog的生命周期,对应viewModelScope会随着Dialog销毁被主动取消,此时如果网络请求还未完成,就会抛出Job was Cancelled异常。- 同时你在Dialog内部对LiveData的观察绑定的是Dialog的生命周期,Dialog销毁后即使请求返回数据,观察者也接收不到回调,自然不会更新Spinner导致空白。
修复方案
必改项
- 修正ViewModel实例获取逻辑
不要在Dialog内部创建绑定自身的ViewModel,改为复用父AddReportFragment的ViewModel,将onDateSet中的代码:
val viewModel = ViewModelProvider(this).get(AddReportViewModel::class.java)
替换为:
val viewModel = ViewModelProvider(requireParentFragment()).get(AddReportViewModel::class.java)
此时ViewModel生命周期和父Fragment绑定,不会随Dialog销毁取消未完成的请求。
- 修正LiveData观察的生命周期宿主
将onDateSet里所有LiveData的observe方法的第一个参数从this(Dialog自身)改为父Fragment的lifecycleOwner,示例如下:
// 修改前 viewModel.mandatoryName.observe(this, Observer { ... }) // 修改后 viewModel.mandatoryName.observe(requireParentFragment().viewLifecycleOwner, Observer { ... })
其余nonMandatoryName、getAll的观察逻辑同理修改,保证Dialog销毁后,父Fragment仍然能正常接收数据回调更新Spinner。
优化项(避免后续隐患)
- 不要在
onDateSet、onItemSelected这类可多次触发的回调里重复注册LiveData观察者,重复注册会导致同一个数据变更触发多次回调。建议把所有LiveData的观察逻辑统一放到AddReportFragment的onCreateView里只注册一次,数据变更自动更新UI。 - 拆分Dialog职责:DatePickerDialog只负责返回选中的日期,不要在内部处理业务逻辑和UI更新,通过接口回调或者父Fragment的ViewModel把选中的日期抛给
AddReportFragment,所有数据请求、UI更新逻辑都在父Fragment内处理,彻底规避生命周期绑定错误的问题。
内容的提问来源于stack exchange,提问作者Jugs
相关产品推荐
相关产品推荐

