Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在某些情况下(单例),从Android上的Globalscope启动协同路由可以吗?_Android_Kotlin_Kotlin Coroutines - Fatal编程技术网

在某些情况下(单例),从Android上的Globalscope启动协同路由可以吗?

在某些情况下(单例),从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(

当从Activities、Fragments或Android Architecture Components ViewModels启动协同路由时,使用绑定到该视图组件生命周期的协同路由范围是完全有意义的,以避免泄漏和释放资源,例如当用户离开屏幕时取消网络请求

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
来轻松测试代码。