在某些情况下(单例)可以从Android的Globalscope启动协程吗?

时间:2019-06-17 13:57:56

标签: android kotlin kotlin-coroutines

从Activity,Fragments或Android体系结构组件ViewModels启动协程时,为了避免泄漏和释放资源,例如,使用绑定到该视图组件生命周期的协程范围是完全有意义的。用户离开屏幕时取消网络请求。

但是在其他情况下,您甚至在用户离开屏幕时也不想取消协程,例如在执行网络分析请求或写入数据库时​​。在这种情况下可以用GlobalScope发起协程吗?发起这些协程的对象大多是Singletons,因此它们在应用程序的整个生命周期中都存在,因此没有泄漏的危险,对吧?

Kotlin文档在GlobalScope上非常清楚:

  

应用程序代码通常应使用应用程序定义的CoroutineScope。不建议在GlobalScope实例上使用异步或启动。

在这些情况下可以使用GlobalScope吗?如果没有,我的应用程序定义的CoroutineScope应该是什么样?

2 个答案:

答案 0 :(得分:1)

如果您的异步工作器的生命周期是真正全局的(它们仅在进程终止时终止/终止),则可以使用GlobalScope或类似的终身范围。

说,您有一个发出请求的活动,但是即使活动消失,实际的网络请求也需要继续,因为您想在网络最终返回响应时对其进行缓存。

您将在“活动/片段”中添加CoroutineScope,或者在ViewModel中添加更好,并使您的代码最终在该范围内运行。当Activity / Fragment / ViewModel死亡时,范围将被取消,并且将不会尝试在不再存在的屏幕上显示任何内容。

但是,您的Fragment / Activity / ViewModel可能会与生命周期仅在进程终止时才结束的数据源/存储库进行通信。您可以在其中切换到GlobalScope ,以便即使没有活动的Activity / Fragment / ViewModel都可以在屏幕上显示结果,也可以缓存您的网络响应。

class MyViewModel(context: CoroutineContext, repo: MyRepository) : ViewModel() {
    private val scope: CoroutineScope(context + SuperviserJob())

    override fun onCleared() { scope.cancel() }

    fun getDataFromNetwork() {
        scope.launch {
            myLiveData.value = repo.getDataFromNetwork()
        }
    }

}

// Singleton class
class MyRepositoryImpl(context: CoroutineContext) : MyRepository {
    private val scope: CoroutineScope(context + SupervisorJob())

    override suspend fun getDataFromNetwork() : String {
        return scope.async { // switch scopes
            val data = ... fetch data ...
            saveInCache(data)
        }.await()
    }
}

当ViewModel结束(调用onCleared)时,MyRepositoryImpl的{​​{1}}仍保持运行,如果一切正常,将调用getDataFromNetwork。但是,返回的值不会分配给saveInCache,因为ViewModel范围的协程已取消。

答案 1 :(得分:0)

鉴于您已经在尝试将其附加到应用程序的生命周期中,建议您将范围传递给您的单例或由其实现协程镜。不幸的是,在GlobalScope上运行协程可能仍然会以泄漏告终。 有关更多信息,请参见Roman Elizarov撰写的这篇精彩文章: https://medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc