Kotlin 协程:避免实体销毁后内部协程仍然继续活动的资源浪费

751 阅读2分钟

在 Kotlin 协程中,一个常见的挑战是如何避免协程在组件(例如 ActivityFragmentViewModel)被销毁后继续执行。如果协程在组件销毁后仍然运行,可能会导致内存泄漏、崩溃和数据不一致等问题。本文将介绍如何有效地避免这种情况。

核心原则:使用 CoroutineScope 并管理其生命周期

Kotlin 协程提供了 CoroutineScope 来管理协程的生命周期。通过使用 CoroutineScope,我们可以在组件被销毁时,自动取消所有在该作用域内启动的协程。

常见场景和解决方案

  1. Android Activity/Fragment:

    • 推荐:使用 lifecycleScopelifecycleScope 自动绑定到 ActivityFragment 的生命周期,并在组件销毁时自动取消协程。

      import androidx.appcompat.app.AppCompatActivity
      import android.os.Bundle
      import kotlinx.coroutines.*
      import androidx.lifecycle.lifecycleScope
      
      class MainActivity : AppCompatActivity() {
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_main)
      
              lifecycleScope.launch {
                  delay(5000)
                  println("协程执行完毕")
              }
          }
      }
      
    • 不推荐:手动创建 CoroutineScope:需要在 onDestroy 方法中手动取消协程,容易出错。

  2. Android ViewModel:

    • 推荐:使用 viewModelScopeviewModelScope 自动绑定到 ViewModel 的生命周期,并在 ViewModel 被清除时自动取消协程。

      import androidx.lifecycle.ViewModel
      import androidx.lifecycle.viewModelScope
      import kotlinx.coroutines.*
      
      class MyViewModel : ViewModel() {
          init {
              viewModelScope.launch {
                  delay(5000)
                  println("协程执行完毕")
              }
          }
      }
      
    • 不推荐:手动创建 CoroutineScope:需要在 onCleared 方法中手动取消协程,容易出错。

  3. 自定义类:

    • 手动创建 CoroutineScope 并管理生命周期:需要在类的生命周期结束时手动取消协程。

      import kotlinx.coroutines.*
      
      class MyClass {
          private val scope = CoroutineScope(Dispatchers.Default)
      
          fun start() {
              scope.launch {
                  delay(5000)
                  println("协程执行完毕")
              }
          }
      
          fun cancel() {
              scope.cancel()
          }
      }
      

最佳实践

  1. 始终使用 CoroutineScope 管理协程生命周期。
  2. Android 中优先使用 lifecycleScopeviewModelScope
  3. 自定义类中手动管理 CoroutineScope 生命周期。
  4. 避免在全局作用域中启动协程。
  5. 使用 isActive 检查协程状态。

总结

通过正确使用 CoroutineScope 并管理其生命周期,可以有效避免协程在组件销毁后继续执行的问题。