在这种情况下,我应该使用哪个协程范围?

huangapple go评论67阅读模式
英文:

What coroutine scope should I use in this case?

问题

I have a view model where I use viewModelScope and everything works perfect in there. Then, I have a class shared by many view models (injected in the constructor). Inside that class I need to call suspend methods and I don't know what's the correct coroutine scope to use.

Right now I'm using GlobalScope but it doesn't sound quite right, I feel the scope of execution should be guided by the owner of this class instance (the view model). I don't understand why if view model uses viewModelScope this injected class should use GlobalScope if not necessary.

I'm quite new with Kotlin so I might be missing something obvious.

英文:

I have a view model where I use viewModelScope and everything works perfect in there. Then, I have a class shared by many view models (injected in the constructor). Inside that class I need to call suspend methods and I don't know what's the correct coroutine scope to use.

Right now I'm using GlobalScope but it doesn't sound quite right, I feel the scope of execution should be guided by the owner of this class instance (the view model). I don't understand why if view model uses viewModelScope this injected class should use GlobalScope if not necessary.

I'm quite new with Kotlin so I might be missing something obvious.

答案1

得分: 2

以下是翻译好的部分:

唯一可以在多个ViewModel之间共享的范围是Singleton范围,因此我假设所讨论的类是以这种方式提供的(否则每个ViewModel都会获得一个新实例,然后可以使用VM范围)。您可以创建一个共享的监督作业,以下是我通常的做法:

@Singleton
open class CoroutinesDispatchers @Inject constructor() {
    open val IO: CoroutineDispatcher = Dispatchers.IO
    open val Main: CoroutineDispatcher = Dispatchers.Main
    open val Default: CoroutineDispatcher = Dispatchers.Default
    open val Unconfined: CoroutineDispatcher = Dispatchers.Unconfined
}

这样可以在单元测试中交换调度程序,并遵循不直接使用Dispatchers.XX的一般建议。实际的范围如下提供:

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class DefaultCoroutineScope

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class UICoroutineScope

@Module
@InstallIn(SingletonComponent::class)
object CoroutinesModule {

    @Provides
    @Singleton
    @DefaultCoroutineScope
    fun defaultCoroutineScope(dispatchers: CoroutinesDispatchers): CoroutineScope = CoroutineScope(
        SupervisorJob() + dispatchers.Default
    )

    @Provides
    @Singleton
    @UICoroutineScope
    fun uiCoroutineScope(dispatchers: CoroutinesDispatchers): CoroutineScope = CoroutineScope(
        SupervisorJob() + dispatchers.Main
    )

}

然后,您只需注入您需要的范围 - 当然,您可以使用其他调度程序(例如IO)或根据需要在启动协程后更改调度程序。基本上,您得到的是一种更可控的方式中的一种全局范围

英文:

The only scope that can be shared between multiple ViewModels is the Singleton scope, so I assume the class in question is provided as such (otherwise you'd get a new instance for every ViewModel and then it's fine to use the VM scope). What you could do is creating a shared supervisor job, here's how I usually go about that:

@Singleton
open class CoroutinesDispatchers @Inject constructor() {
    open val IO: CoroutineDispatcher = Dispatchers.IO
    open val Main: CoroutineDispatcher = Dispatchers.Main
    open val Default: CoroutineDispatcher = Dispatchers.Default
    open val Unconfined: CoroutineDispatcher = Dispatchers.Unconfined
}

^^ this one allows you to swap out the dispatchers in unit tests and follows the general recommendation not to use Dispatchers.XX directly. The actual scopes are provided as follows:

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class DefaultCoroutineScope

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class UICoroutineScope

@Module
@InstallIn(SingletonComponent::class)
object CoroutinesModule {

    @Provides
    @Singleton
    @DefaultCoroutineScope
    fun defaultCoroutineScope(dispatchers: CoroutinesDispatchers): CoroutineScope = CoroutineScope(
        SupervisorJob() + dispatchers.Default
    )

    @Provides
    @Singleton
    @UICoroutineScope
    fun uiCoroutineScope(dispatchers: CoroutinesDispatchers): CoroutineScope = CoroutineScope(
        SupervisorJob() + dispatchers.Main
    )

}

Then you just inject the scope you need - you could of course use other dispatchers (e.g. IO) or change the dispatcher after launching a coroutine according to your needs. Basically what you get is a kind of a GlobalScope in a more controllable manner.

huangapple
  • 本文由 发表于 2023年6月26日 19:46:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76556376.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定