在Android上启动协同程序的正确方法是什么?

时间:2019-11-26 22:18:06

标签: android kotlin-coroutines

我正在尝试找出如何启动协程。我希望它依次调用两个暂停函数。

我阅读的第一份文档说是这样做的:

class Something {
  fun initialize() {
    launch {
      suspendFun1()
      suspendFun2()
    }
}

但是Android Studio找不到launch方法。然后我了解到official coroutine docs建议使用GlobalScope.launch

class Something {
  fun initialize() {
    GlobalScope.launch {
      suspendFun1()
      suspendFun2()
    }
}

但是我在this post中读到,您不应该使用GlobalScope.launch

因此,我找到了另一个blog post,解释说我需要一个CoroutineScope来调用launch。但这并没有说明如何构建一个。

然后,我发现这个blog post解释了如何通过在类上实现CoroutineScope来为Activity和ViewModel构建对象:

class Something : CoroutineScope {
  private lateinit var job: Job
  override val coroutineContext: CoroutineContext
        get() = job + Dispatchers.Main

  fun initialize() {
    job = Job()
    launch {
      suspendFun1()
      suspendFun2()
    }
}

然后我读了blog post,说我不应该实现CoroutineScope

class Something {
  protected val scope = CoroutineScope(
    Job() + Dispatchers.Main
  )

  fun initialize() {
    scope.launch {
      suspendFun1()
      suspendFun2()
    }
}

但是我不确定我是否了解Job() + Dispatchers.Main的含义,因为这似乎也可以工作:

class Something {
  protected val scope = CoroutineScope(Dispatchers.Main)

  fun initialize() {
    scope.launch {
      suspendFun1()
      suspendFun2()
    }
}

有人可以简单地向我解释最好的方法吗?如上吗?我确定已经有人问过这个问题,因此对这个重复的问题我深表歉意。但是如您所见,对此尚无明确答案。我想听听您的意见。

3 个答案:

答案 0 :(得分:1)

最后两种解决方案都可以。如果您传递不带上下文的上下文,则CoroutineScope(context: CoroutineContext)将创建一个空的Job

指定job + dispatcher是一种更为明确的构建方式,因为在某些情况下,您可能想使用SupervisorJob来防止在子作业之一失败时取消整个作用域。

关于在ActivitiesViewModels中构建作用域,您无需声明自己的作用域,而可以通过导入KTX片段模块来使用KTX库中内置的作用域:

// add to your apps dependencies
implementation 'androidx.fragment:fragment-ktx:1.2.0-rc02'

现在在ActivityFragment内,您可以使用lifecycleScope,并在ViewModelviewModelScope内使用SupervisorJob + Dispatchers.Main.immediate支持的范围并在其各自的生命周期被破坏时自动取消。

答案 1 :(得分:0)

我有Coroutines.kt

object Coroutines {

    fun main(work: suspend (() -> Unit)) {
        CoroutineScope(Dispatchers.Main).launch {
            work()
        }
    }

}

然后我通过调用Couroutines.main在我的视图模型中使用它

答案 2 :(得分:0)

我陷入了非常相似的困境,OP 出色地捕捉到了新手对各种资源的困惑。就我而言,除了创建自己的 CoroutineScope 之外,我别无选择,因为我需要一个长期运行的作用域,它的生命周期与应用进程的生命周期一样长(它使用挂起函数处理与 Retrofit 的交互),并且它一直存在在 Android 库中,无法访问 ViewModel 和其他 LifecycleOwner 项。

/**
 * A [CoroutineScope] for HTTP cloud implementations to launch coroutines in. A coroutine
 * dispatcher is not specified because Retrofit will switch to its own custom dispatcher
 * when performing suspending network calls.
 */
internal val networkingScope = CoroutineScope(SupervisorJob())
相关问题