在某些情况下(单例),从Android上的Globalscope启动协同路由可以吗?
当从Activities、Fragments或Android Architecture Components ViewModels启动协同路由时,使用绑定到该视图组件生命周期的协同路由范围是完全有意义的,以避免泄漏和释放资源,例如当用户离开屏幕时取消网络请求在某些情况下(单例),从Android上的Globalscope启动协同路由可以吗?,android,kotlin,kotlin-coroutines,Android,Kotlin,Kotlin Coroutines,当从Activities、Fragments或Android Architecture Components ViewModels启动协同路由时,使用绑定到该视图组件生命周期的协同路由范围是完全有意义的,以避免泄漏和释放资源,例如当用户离开屏幕时取消网络请求 class MyViewModel(context: CoroutineContext, repo: MyRepository) : ViewModel() { private val scope = CoroutineScope(
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()
}
}
但也有其他情况,在这种情况下,即使用户离开屏幕,您也不想取消协同路由,就像您执行网络分析请求或写入数据库时一样。在这种情况下,是否可以启动与GlobalScope
的协同路由?启动这些协同路由的对象大多是单例
,因此它们在应用程序的整个生命周期中都存在,所以没有泄漏的危险,对吗
Kotlin文档在GlobalScope上非常清晰:
应用程序代码通常应该使用应用程序定义的协同作用域。强烈反对在GlobalScope实例上使用async或launch
在这些情况下使用GlobalScope可以吗?如果不是,我的应用程序定义的协同作用域应该是什么样子?鉴于您已经尝试将其附加到应用程序的生命周期中,我建议将作用域传递给您的singleton,或者通过它实现协同作用域。不幸的是,在GlobalScope上运行协同程序仍可能导致泄漏。 有关更多信息,请参阅Roman Elizarov的这篇伟大文章:
如果您有一个异步工作进程,其生命周期是真正的全局的(只有当您的进程死亡时它们才会死亡/结束),使用
GlobalScope
或类似的终身范围是可以的
比如说,您有一个发出请求的活动,但即使活动消失,实际的网络请求也需要继续,因为您希望在网络最终返回响应时对其进行缓存
您将在活动/片段中添加一个CoroutineScope
,或在ViewModel中添加一个better,并让您的代码最终在该范围内运行屏幕上的内容。当Activity/Fragment/ViewModel终止时,将取消作用域,并且不会尝试在屏幕上显示不再存在的内容
但是,您的片段/活动/视图模型可能会与具有生命周期的数据源/存储库通信,该生命周期仅在流程结束时结束。您可以切换到其中的GlobalScope,以便缓存网络响应,即使没有活动/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
的getDataFromNetwork
仍在运行,如果一切正常,将调用saveInCache
。但是,返回的值不会分配给myLiveData.value
,因为ViewModel作用域的协同程序已取消。谢谢您的回答!我有两个问题:1。在getDataFromNetwork()
函数中使用.async和.wait有什么原因吗?它是否与使用with context(context)
相同?2.您将什么类型的CoroutineContext传递给MyRepositoryImpl
的构造函数?使用withContext
只切换上下文,而不是范围。这主要用于切换调度器等。对于上下文
参数到MyRepositoryImpl
;例如,您可以通过TestCoroutineDispatcher
来轻松测试代码。