从Activity,Fragments或Android体系结构组件ViewModels启动协程时,为了避免泄漏和释放资源,例如,使用绑定到该视图组件生命周期的协程范围是完全有意义的。用户离开屏幕时取消网络请求。
但是在其他情况下,您甚至在用户离开屏幕时也不想取消协程,例如在执行网络分析请求或写入数据库时。在这种情况下可以用GlobalScope
发起协程吗?发起这些协程的对象大多是Singletons
,因此它们在应用程序的整个生命周期中都存在,因此没有泄漏的危险,对吧?
Kotlin文档在GlobalScope上非常清楚:
应用程序代码通常应使用应用程序定义的CoroutineScope。不建议在GlobalScope实例上使用异步或启动。
在这些情况下可以使用GlobalScope吗?如果没有,我的应用程序定义的CoroutineScope应该是什么样?
答案 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