kotlin 协程: GlobalScope 和 Application Scope 选择和使用 —— 新手指南

在 Kotlin 协程中,选择正确的 Scope 非常重要。本文将详细解释 GlobalScope 和 Application Scope(通常指 CoroutineScope)的区别和使用场景。

📌 1. GlobalScope

特点:

  • 全局生命周期:跟随整个应用进程
  • 不会自动取消:除非应用进程结束
  • 谨慎使用:容易造成内存泄漏

使用示例:

kotlin 复制代码
// ⚠️ 不推荐 - 容易造成内存泄漏
fun riskyMethod() {
    GlobalScope.launch {
        // 长时间运行的任务
        delay(5000)
        updateUI() // 可能已经销毁的 Activity 中调用
    }
}

// 需要手动管理
var job: Job? = null

fun startTask() {
    job = GlobalScope.launch {
        // 执行任务
    }
}

fun stopTask() {
    job?.cancel()
}

📌 2. Application Scope(推荐)

创建方式:

kotlin 复制代码
// 方式1:自定义 Application Scope
class MyApplication : Application() {
    // 自定义 Application Scope
    val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
    
    override fun onCreate() {
        super.onCreate()
        // 初始化
    }
    
    override fun onTerminate() {
        applicationScope.cancel()
        super.onTerminate()
    }
}

// 方式2:使用 AndroidX 的 Lifecycle
class MyApplication : Application() {
    val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
}

📌 3. ViewModel Scope

在 Android 中更推荐使用 ViewModel 的 scope:

kotlin 复制代码
class MyViewModel : ViewModel() {
    
    // ViewModel 自带 viewModelScope
    fun fetchData() {
        viewModelScope.launch {
            // 自动跟随 ViewModel 生命周期
            val data = repository.getData()
            _uiState.value = data
        }
    }
    
    // 或者创建自定义 scope
    private val customScope = CoroutineScope(
        SupervisorJob() + Dispatchers.IO
    )
    
    override fun onCleared() {
        super.onCleared()
        customScope.cancel()
    }
}

📌 4. Lifecycle Scope

kotlin 复制代码
class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // lifecycleScope 自动跟随生命周期
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                // 只在 STARTED 状态执行
                collectData()
            }
        }
        
        // 或者使用 launchWhenStarted
        lifecycleScope.launchWhenStarted {
            // 当 Activity 进入 STARTED 状态时恢复
        }
    }
}

📌 5. 对比表格

特性 GlobalScope Application Scope ViewModel Scope Lifecycle Scope
生命周期 应用进程 自定义控制 ViewModel 生命周期 Activity/Fragment 生命周期
自动取消 ❌ 否 ✅ 可自定义 ✅ 是 ✅ 是
推荐使用 ❌ 很少 ✅ 后台任务 ✅ ViewModel 中 ✅ UI 相关
内存安全 ❌ 危险 ✅ 可控 ✅ 安全 ✅ 安全

📌 6. 最佳实践

✅ 推荐做法:

kotlin 复制代码
// 1. 在 Application 中创建全局 scope
class MyApp : Application() {
    val appScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    
    companion object {
        lateinit var instance: MyApp
            private set
    }
    
    override fun onCreate() {
        super.onCreate()
        instance = this
    }
}

// 2. 使用 ViewModel scope(首选)
class UserViewModel(
    private val userRepository: UserRepository
) : ViewModel() {
    
    fun loadUser(userId: String) {
        viewModelScope.launch {
            _loading.value = true
            try {
                val user = userRepository.getUser(userId)
                _user.value = user
            } catch (e: Exception) {
                _error.value = e.message
            } finally {
                _loading.value = false
            }
        }
    }
}

// 3. 需要全局后台任务时
class AnalyticsService(context: Context) {
    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    
    fun logEvent(event: String) {
        scope.launch {
            // 发送分析事件到服务器
            sendToServer(event)
        }
    }
    
    fun cleanup() {
        scope.cancel()
    }
}

📌 7. 总结建议

1). 几乎不要使用 GlobalScope,除非:

  • 编写测试代码
  • 编写一次性脚本
  • 明确知道任务需要一直运行到应用结束

2). 按层次选择 Scope:

  • UI 更新 → lifecycleScope 或 viewModelScope
  • 业务逻辑 → viewModelScope
  • 全局后台任务 → Application Scope
  • 数据库/网络 → IO Dispatcher + 合适的 Scope

3).遵循原则:

  • 生命周期感知:协程应该能被正确取消
  • 结构化并发:使用父-子协程关系
  • 异常处理 :使用 SupervisorJob 防止一个协程失败影响其他

协程创建的成本很低,但内存泄漏的成本很高。选择合适的 Scope 是编写健壮协程代码的关键。

相关推荐
游戏开发爱好者816 分钟前
抓包工具有哪些?代理抓包、数据流抓包、拦截转发工具
android·ios·小程序·https·uni-app·iphone·webview
StarShip27 分钟前
Android system_server进程介绍
android
StarShip30 分钟前
Android Context 的 “上下文”
android
成都大菠萝30 分钟前
2-6-1 快速掌握Kotlin-语言的接口定义
android
李小轰_Rex1 小时前
纯算法AEC:播录并行场景的回声消除实战笔记
android·音视频开发
ok406lhq2 小时前
unity游戏调用SDK支付返回游戏会出现画面移位的问题
android·游戏·unity·游戏引擎·sdk
IT乐手2 小时前
在 Kotlin 中创建 DSL
kotlin
成都大菠萝3 小时前
2-2-2 快速掌握Kotlin-函数&Lambda
android
成都大菠萝3 小时前
2-1-1 快速掌握Kotlin-kotlin中变量&语句&表达式
android
CC.GG3 小时前
【C++】STL----封装红黑树实现map和set
android·java·c++