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

Phi*_*lly 13 android kotlin-coroutines

我想弄清楚如何启动协程。我希望它按顺序调用两个挂起函数。

我阅读的第一个文档说要这样做:

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

Run Code Online (Sandbox Code Playgroud)

但是launchAndroid Studio没有找到该方法。然后我了解到官方协程文档建议使用GlobalScope.launch

class Something {
  fun initialize() {
    GlobalScope.launch {
      suspendFun1()
      suspendFun2()
    }
}
Run Code Online (Sandbox Code Playgroud)

但后来我在这篇文章中读到,你不应该使用GlobalScope.launch.

所以我找到了另一篇博文,解释说我需要一个 CoroutineScope 来调用launch. 但它没有解释如何构建一个。

然后我找到了这篇博客文章,解释了如何通过在类上实现 CoroutineScope 来为活动和视图模型构建一个:

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

  fun initialize() {
    job = Job()
    launch {
      suspendFun1()
      suspendFun2()
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我读了这篇博文说我不应该实施CoroutineScope

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

  fun initialize() {
    scope.launch {
      suspendFun1()
      suspendFun2()
    }
}
Run Code Online (Sandbox Code Playgroud)

但我不确定我是否理解 的含义Job() + Dispatchers.Main,因为这似乎也有效:

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

  fun initialize() {
    scope.launch {
      suspendFun1()
      suspendFun2()
    }
}
Run Code Online (Sandbox Code Playgroud)

有人可以简单地向我解释这样做的最佳方法吗?是不是如上?我确定这已经被问过了,所以如果这是一个重复的问题,我深表歉意。但正如你所看到的,对此并没有明确的答案。我想听听您的意见。

Ber*_*mpl 18

对于那些只是寻找一种简单的方法来启动具有 Android Activity 的协程而不需要所有花哨功能的人,这里有一个快速而简单的方法(但您仍然应该学习如何正确使用协程,即使用 ViewModels 和 CoroutineScope)

  1. androidx.lifecycle添加到您的应用程序级 build.gradle 中:

implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1"(查看上面的链接了解当前版本)

  1. 在Activity中,使用Activity提供的LifecycleScope来启动Coroutine(大部分是伪代码):
import androidx.lifecycle.lifecycleScope

class YourActivity {

  override fun onCreate() {
    lifecycleScope.launch {
      // do your Coroutine Stuff here, i.e. call a suspend fun:
      coroutineFunction()
    }
  }

  suspend fun coroutineFunction() {
    // Use a different CoroutineScope, etc
    CoroutineScope(Dispatchers.IO).launch {
      // do some long running operation or something
    }
  }

}
Run Code Online (Sandbox Code Playgroud)


Paw*_*wel 9

最后两个解决方案很好。如果您传递一个没有上下文的上下文,CoroutineScope(context: CoroutineContext)则会创建一个空的Job

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

至于构建范围,ActivitiesViewModels不是声明自己的范围,您可以通过导入 KTX 片段模块来使用内置到 KTX 库中的范围:

// add to your apps dependencies
implementation 'androidx.fragment:fragment-ktx:1.2.0-rc02'
Run Code Online (Sandbox Code Playgroud)

现在,在您的Activitys 和Fragments 中,您可以使用lifecycleScope和 在ViewModela 中viewModelScope,它们是受支持的范围,SupervisorJob + Dispatchers.Main.immediate并且在它们各自的生命周期被销毁时会自动取消。


小智 5

我有 Coroutines.kt

object Coroutines {

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

}
Run Code Online (Sandbox Code Playgroud)

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

  • 哇,我不知道你可以做一个暂停 lambda (2认同)
  • 请不要这样做,它可能会泄漏协程。自定义的 CoroutineScope 应该根据某个生命周期正确取消,否则它们和 GlobalScope 一样糟糕。这就是为什么建议使用内置的“lifecycleScope”或“viewModelScope”。 (2认同)