简体   繁体   中英

Android kotlin coroutines, viewModelScope behavior

I am having this interesting problem. I need to do some work immediately after insertion, but viewModelScope randomly, or at least it looks like randomly, skips functions except for the first one.

Example:

fun insertItem(item: SingleItem) = viewModelScope.launch {
        itemsRepository.insertItem(item)
        increaseAmount(item.catId)
    }

So in this example everything runs ok only after fresh app install, but then on the next app launches second function "increaseAmount" will be randomly skipped and i don`t know why. And it doesn't matter what goes after first function. I tried simple "Log" and it gets skipped as well. Is it normal for viewModelScope?

EDIT Checked for exceptions. Second function throws an exception that the job was cancelled:

kotlinx.coroutines.JobCancellationException: Job was cancelled; job=SupervisorJobImpl{Cancelling}@2d87ff

Also, in my Fragment it is called like this:

viewModel.insertItem(newItem)
root.findNavController().popBackStack()

So after calling this function i go back to previous Fragment. Is it possible that viewModel gets destroyed before it finishes executing all work?

Is it normal for viewModelScope?

No, it is not. In coroutines functions call must be sequential. Functions itemsRepository.insertItem(item) and increaseAmount(item.catId) must be called one after another. I see a couple of reasons why second function is not called:

  1. Function itemsRepository.insertItem(item) throws some exception.
  2. Current coroutine scope is cancelled before second function call.

Edit :

ViewModel objects are scoped to the Lifecycle passed to the ViewModelProvider when getting the ViewModel . The ViewModel remains in memory until the Lifecycle it's scoped to goes away permanently: in the case of an activity, when it finishes, while in the case of a fragment, when it's detached.

After you call root.findNavController().popBackStack() your fragment will be detached, the ViewModel cleared and coroutine job cancelled. You can initialize the ViewModel in the fragment in the following way:

private val viewModel: YourViewModel by activityViewModels()

Initializing viewModel in this way it will be scoped to the Lifecycle of an Activity .

To use activityViewModels() add next line to the dependencies of app's build.gradle file:

implementation "androidx.fragment:fragment-ktx:1.2.5"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM