在 Android 中取消与 liveData 的协程
Cancel coroutine with liveData in Android
我有一个应用程序可以与 Retrofit2、liveData 和 Coroutines 一起使用,以通过我的 API 获取信息。我需要取消工作,如果我们开始新的工作,我会尝试使用 Job.cancel(),但是出了点问题。
这是我的 ViewModel:
class MembersViewModel(private val memberRepository: MemberRepository) : ViewModel() {
private var job = Job()
fun getMembers(category: String, year: String) = liveData(job + Dispatchers.IO) {
emit(Resource.loading(null))
try {
val data = memberRepository.getMembers(category, year)
if (year == "2008") delay(6000)
if (data.isSuccessful) emit(Resource.success(data)) else emit(Resource.serverError(data))
} catch (exception: Exception) {
emit(Resource.error(null, exception.message ?: "Error occurred."))
}
}
fun cancelJob() {
job.cancel()
}
}
Fragment,我在其中调用了 ViewModel:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
setViewModel()
//some code
binding.membersChipGroup.setOnCheckedChangeListener { chipGroup, chipId ->
//some code
setObservers(binding, year)
}
return binding.root
}
private fun setViewModel() {
viewModel = ViewModelProvider(this, ViewModelFactory(ApiHelper(RetrofitBuilder.apiService))).get(MembersViewModel::class.java)
}
private fun setObservers(binding: FragmentOfMembersViewPagerBinding, year: String) {
viewModel?.cancelJob()
viewModel?.getMembers(raceType, year)?.observe(viewLifecycleOwner, Observer { resource ->
when (resource.status) {
Resource.Status.SUCCESS -> {
resource.data?.let { members ->
binding.mtv1.text = members.body()?.last().toString()
}
}
Resource.Status.ERROR -> {
//some code
}
Resource.Status.LOADING -> {
//some code
}
Resource.Status.SERVER_ERROR -> {
//some code
}
}
})
}
如果我调用 viewModel?.cancelJob()
,那么 viewModel?.getMembers(raceType, year)
不起作用,但是如果我删除行 viewModel?.cancelJob()
一切正常,但我无法取消 viewModel?.getMembers(raceType, year)
.
原因是您在使用 Job
之前先取消它,Coroutine Jobs
一旦变为非活动状态就不应使用,否则将无法使用。要在 ViewModel
中取消现有 Job
后实现此目的,只需创建一个新的 instance
并分配它,它将按预期工作
ViewModel
fun cancelJob() {
job.cancel() //instance marked as stale, once cancelled
job = Job() //new instance will work
}
我有一个应用程序可以与 Retrofit2、liveData 和 Coroutines 一起使用,以通过我的 API 获取信息。我需要取消工作,如果我们开始新的工作,我会尝试使用 Job.cancel(),但是出了点问题。
这是我的 ViewModel:
class MembersViewModel(private val memberRepository: MemberRepository) : ViewModel() {
private var job = Job()
fun getMembers(category: String, year: String) = liveData(job + Dispatchers.IO) {
emit(Resource.loading(null))
try {
val data = memberRepository.getMembers(category, year)
if (year == "2008") delay(6000)
if (data.isSuccessful) emit(Resource.success(data)) else emit(Resource.serverError(data))
} catch (exception: Exception) {
emit(Resource.error(null, exception.message ?: "Error occurred."))
}
}
fun cancelJob() {
job.cancel()
}
}
Fragment,我在其中调用了 ViewModel:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
setViewModel()
//some code
binding.membersChipGroup.setOnCheckedChangeListener { chipGroup, chipId ->
//some code
setObservers(binding, year)
}
return binding.root
}
private fun setViewModel() {
viewModel = ViewModelProvider(this, ViewModelFactory(ApiHelper(RetrofitBuilder.apiService))).get(MembersViewModel::class.java)
}
private fun setObservers(binding: FragmentOfMembersViewPagerBinding, year: String) {
viewModel?.cancelJob()
viewModel?.getMembers(raceType, year)?.observe(viewLifecycleOwner, Observer { resource ->
when (resource.status) {
Resource.Status.SUCCESS -> {
resource.data?.let { members ->
binding.mtv1.text = members.body()?.last().toString()
}
}
Resource.Status.ERROR -> {
//some code
}
Resource.Status.LOADING -> {
//some code
}
Resource.Status.SERVER_ERROR -> {
//some code
}
}
})
}
如果我调用 viewModel?.cancelJob()
,那么 viewModel?.getMembers(raceType, year)
不起作用,但是如果我删除行 viewModel?.cancelJob()
一切正常,但我无法取消 viewModel?.getMembers(raceType, year)
.
原因是您在使用 Job
之前先取消它,Coroutine Jobs
一旦变为非活动状态就不应使用,否则将无法使用。要在 ViewModel
中取消现有 Job
后实现此目的,只需创建一个新的 instance
并分配它,它将按预期工作
ViewModel
fun cancelJob() {
job.cancel() //instance marked as stale, once cancelled
job = Job() //new instance will work
}