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



当从活动、片段或 Android 架构组件 ViewModel 启动协程时,使用绑定到该视图组件生命周期的协程作用域是完全有意义的,以避免泄漏和释放资源,例如在用户离开屏幕时取消网络请求。

但在其他情况下,即使用户离开屏幕,您也不想取消协程,例如当您执行网络请求进行分析或写入数据库时。在这种情况下,是否可以启动带有GlobalScope的协程?启动这些协程的对象大多是Singletons的,因此它们无论如何都存在于应用程序的生命周期中,因此没有泄漏的危险,对吧?

Kotlin 文档在 GlobalScope 上非常清楚:

应用程序

代码通常应使用应用程序定义的协程范围。强烈建议不要在 GlobalScope 实例上使用异步或启动。

在这些情况下可以使用全球范围吗?如果不是,我的应用程序定义的协程范围应该是什么样子的?

如果你有一个异步工作线程,其生命周期是真正的全局的(它们只在你的进程死亡时死亡/结束),使用GlobalScope或类似的终身范围,是可以的。

假设您有一个发出请求的活动,但即使该活动消失,实际的网络请求也需要继续,因为您希望在网络最终返回响应时缓存它。

您将向活动/片段添加CoroutineScope,或者更好地添加到 ViewModel,并让最终将内容放在屏幕上的代码在该范围内运行。当活动/片段/视图模型死亡时,范围将被取消,并且不会尝试在不再存在的屏幕上显示任何内容。

但是,您的片段/活动/视图模型可能会与数据源/存储库通信,该数据源/存储库的生命周期仅在进程死亡时结束。您可以切换到其中的 GlobalScope,以便缓存您的网络响应,即使没有活动/片段/视图模型处于活动状态以在屏幕上显示结果。

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),MyRepositoryImplgetDataFromNetwork仍然保持运行,如果一切正常,将调用saveInCache。但是,返回的值不会分配给myLiveData.value因为 ViewModel 作用域的协程已取消。

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

相关内容

  • 没有找到相关文章

最新更新