【问题标题】:Am I canceling coroutines correctly我是否正确取消协程
【发布时间】:2019-05-03 20:38:56
【问题描述】:

我有这样的视图模型

class StorageValidationViewModel: ViewModel(), CoroutineScope {

    //Coroutines
    private val _job = SupervisorJob()
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + _job

    override fun onCleared() {
        super.onCleared()
        coroutineContext.cancel()
    }
    ......
}

我有一些方法可以通过Retrofit 发起网络调用来启动协程

fun getStorageLocations(){
        launch {
            var locations:List<StorageLocationData>? = null
            try {
                locations = _storageLocationRepository.getAllStorageLocations()
            }catch (e:IOException){
                e.printStackTrace()
            }

            storageLocationsLiveData.postValue(locations)
        }
    }

一切正常,但我感觉当 ViewModel 被清除时我没有正确取消协程,因为我实际上并没有在任何地方使用 coroutineContext 从而造成内存泄漏

我应该这样做吗

launch(coroutineContext){
    //API call?
}

还是我做得很好?我只是想确保我所做的事情不会造成内存泄漏

【问题讨论】:

  • launchCoroutineScope 的扩展方法,你的ViewModel 实现了它,所以看起来不错。另一个问题是,除非您的 getAllStorageLocations 是暂停方法,否则它可能不知道取消,并且无论如何都会继续执行。
  • @Pawel 是的 getAllStorageLocationssuspend fun 因为改造 api 在拨打电话时使用 await
  • 一切正常

标签: android kotlin android-architecture-components android-viewmodel kotlin-coroutines


【解决方案1】:

您的实现不会造成内存泄漏。 coroutineContext: CoroutineContext 是从CoroutineScope 继承时必须实现的属性。使用 launch 协程构建器启动协程时,它使用覆盖的 coroutineContext 上下文,因此您无需将其显式传递给 launch() 构建器。

ViewModel 中使用协程有更直接的方法。 viewModelScope 属性可用于启动协程,而无需从 CoroutineScope 继承:

class MyViewModel: ViewModel() {
    init {
        viewModelScope.launch {
            // Coroutine that will be canceled when the ViewModel is cleared.
        }
    }
}

并且无需在onCleared() 方法中显式取消作业。

对于viewModelScope,请使用androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0 或更高版本。

【讨论】:

    猜你喜欢
    • 2020-04-29
    • 2013-07-25
    • 2013-04-14
    • 2020-12-01
    • 2021-09-13
    • 1970-01-01
    • 2021-11-21
    • 1970-01-01
    • 2015-02-01
    相关资源
    最近更新 更多