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

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

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范围)。您可以创建一个共享的监督作业,以下是我通常的做法:

  1. @Singleton
  2. open class CoroutinesDispatchers @Inject constructor() {
  3. open val IO: CoroutineDispatcher = Dispatchers.IO
  4. open val Main: CoroutineDispatcher = Dispatchers.Main
  5. open val Default: CoroutineDispatcher = Dispatchers.Default
  6. open val Unconfined: CoroutineDispatcher = Dispatchers.Unconfined
  7. }

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

  1. @Qualifier
  2. @Retention(AnnotationRetention.BINARY)
  3. annotation class DefaultCoroutineScope
  4. @Qualifier
  5. @Retention(AnnotationRetention.BINARY)
  6. annotation class UICoroutineScope
  7. @Module
  8. @InstallIn(SingletonComponent::class)
  9. object CoroutinesModule {
  10. @Provides
  11. @Singleton
  12. @DefaultCoroutineScope
  13. fun defaultCoroutineScope(dispatchers: CoroutinesDispatchers): CoroutineScope = CoroutineScope(
  14. SupervisorJob() + dispatchers.Default
  15. )
  16. @Provides
  17. @Singleton
  18. @UICoroutineScope
  19. fun uiCoroutineScope(dispatchers: CoroutinesDispatchers): CoroutineScope = CoroutineScope(
  20. SupervisorJob() + dispatchers.Main
  21. )
  22. }

然后,您只需注入您需要的范围 - 当然,您可以使用其他调度程序(例如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:

  1. @Singleton
  2. open class CoroutinesDispatchers @Inject constructor() {
  3. open val IO: CoroutineDispatcher = Dispatchers.IO
  4. open val Main: CoroutineDispatcher = Dispatchers.Main
  5. open val Default: CoroutineDispatcher = Dispatchers.Default
  6. open val Unconfined: CoroutineDispatcher = Dispatchers.Unconfined
  7. }

^^ 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:

  1. @Qualifier
  2. @Retention(AnnotationRetention.BINARY)
  3. annotation class DefaultCoroutineScope
  4. @Qualifier
  5. @Retention(AnnotationRetention.BINARY)
  6. annotation class UICoroutineScope
  7. @Module
  8. @InstallIn(SingletonComponent::class)
  9. object CoroutinesModule {
  10. @Provides
  11. @Singleton
  12. @DefaultCoroutineScope
  13. fun defaultCoroutineScope(dispatchers: CoroutinesDispatchers): CoroutineScope = CoroutineScope(
  14. SupervisorJob() + dispatchers.Default
  15. )
  16. @Provides
  17. @Singleton
  18. @UICoroutineScope
  19. fun uiCoroutineScope(dispatchers: CoroutinesDispatchers): CoroutineScope = CoroutineScope(
  20. SupervisorJob() + dispatchers.Main
  21. )
  22. }

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:

确定