简体   繁体   English

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

[英]Is it OK to launch coroutines from Globalscope on Android in certain situations (singletons)?

When launching coroutines from Activities, Fragments or Android Architecture Components ViewModels, it makes total sense to use a coroutine scope that is bound to the lifecycle of that view component in order to avoid leaks and free resources by eg canceling the network request when the user leaves the screen.当从活动、片段或 Android 架构组件视图模型启动协程时,使用绑定到该视图组件生命周期的协程范围是完全有意义的,以避免泄漏和释放资源,例如在用户离开时取消网络请求屏幕。

But there are other situations, where you don't want to cancel a coroutine even when the user leaves the screen like when you are performing a network request for analytics or writing into a database.但在其他情况下,即使用户离开屏幕,您也不想取消协程,例如执行网络请求进行分析或写入数据库时​​。 Is it OK to launch coroutines with GlobalScope in such situations?在这种情况下,可以使用GlobalScope启动协程吗? The objects where these coroutines are launched are mostly Singletons , so they live for the lifetime of the application anyway, so there is no danger of leaks, right?启动这些协程的对象大多是Singletons ,所以它们无论如何都会在应用程序的生命周期中存在,所以没有泄漏的危险,对吧?

The Kotlin docs are pretty clear on GlobalScope:在 GlobalScope 上,Kotlin 文档非常清楚:

Application code usually should use an application-defined CoroutineScope.应用程序代码通常应该使用应用程序定义的 CoroutineScope。 Using async or launch on the instance of GlobalScope is highly discouraged.强烈建议不要在 GlobalScope 实例上使用 async 或 launch。

Is it OK to use GlobalScope in these situations?在这些情况下可以使用 GlobalScope 吗? If not, how should my application-defined CoroutineScope look like?如果不是,我的应用程序定义的 CoroutineScope 应该是什么样的?

If you have an asynchronous worker whose lifecycles is truly global (they only die/end when your process dies), using GlobalScope or a similar life-long scope, is fine.如果您有一个生命周期真正全局化的异步工作线程(它们只会在您的进程终止时终止/终止),那么使用GlobalScope或类似的终身作用域就可以了。

Say, you have an Activity that makes a request, but the actual network-request needs to continue even if the Activity goes away, because you'd like to cache it when the network finally returns a response.假设您有一个发出请求的 Activity,但即使 Activity 消失,实际的网络请求也需要继续,因为您希望在网络最终返回响应时缓存它。

You'll add a CoroutineScope to your Activity/Fragment, or better to your ViewModel and have your code that finally puts stuff on the screen run in that scope.您将CoroutineScope添加到您的 Activity/Fragment,或者更好地添加到您的 ViewModel,并让您的代码最终在该范围内运行屏幕上的内容。 When the Activity/Fragment/ViewModel dies, the scope is canceled and nothing will be attempted to show something on a screen that no longer exists.当 Activity/Fragment/ViewModel 死亡时,范围将被取消,并且不会尝试在不再存在的屏幕上显示任何内容。

However, your Fragment/Activity/ViewModel may talk to a data-source/repository that has a lifecycle that only ends when the process dies.但是,您的 Fragment/Activity/ViewModel 可能会与具有生命周期的数据源/存储库对话,该生命周期仅在进程终止时结束。 You can switch to a GlobalScope in there so that your network-responses get cached, even when no Activity/Fragment/ViewModel is alive to show the result on the screen.您可以在那里切换到 GlobalScope,以便缓存您的网络响应,即使没有活动/片段/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()
    }
}

When your ViewModel ends ( onCleared is called), the MyRepositoryImpl 's getDataFromNetwork still keeps running and will call saveInCache if all goes right.当您的 ViewModel 结束时( onCleared被调用), MyRepositoryImplgetDataFromNetwork仍然保持运行,如果一切顺利,将调用saveInCache However, the value returned won't be assigned to myLiveData.value because the coroutine of your ViewModel's scope was cancelled.但是,返回的值不会分配给myLiveData.value因为您的 ViewModel 范围的协程被取消。

Given that you're already trying to attach it to application's lifecycle, I'd suggest either passing the scope to your singleton or implementing a coroutinescope by it.鉴于您已经尝试将它附加到应用程序的生命周期,我建议要么将作用域传递给您的单例,要么通过它实现一个协程作用域。 Unfortunately, running coroutines on GlobalScope still might end in leaks.不幸的是,在 GlobalScope 上运行协程仍然可能以泄漏告终。 See this great article by Roman Elizarov for more info: https://medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc有关更多信息,请参阅 Roman Elizarov 的这篇精彩文章: https : //medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM