资讯动态

Kotlin 协程作用域源码剖析

发布时间:2026/10/18 4:09:47 来源:尧图企业网站定制
GlobalScope、MainScope、lifecycleScope、viewModelScope 四者的实现原理与正确使用姿势1. viewModelScopeclassMyViewModel:ViewModel(){funloadData(){viewModelScope.launch{// 在这里启动的协程会自动绑定 ViewModel 生命周期// ViewModel 被清理时协程会被取消}}}源码分析// 用 ViewModel 的 tag 机制缓存 CoroutineScope保证一个 ViewModel 实例只有一个 ScopeprivateconstvalJOB_KEYandroidx.lifecycle.ViewModelCoroutineScope.JOB_KEYvalViewModel.viewModelScope:CoroutineScopeget(){// 1. 先从 ViewModel 的 Tag 缓存中读取valscope:CoroutineScope?this.getTag(JOB_KEY)if(scope!null){returnscope}// 2. 首次访问时创建使用 SupervisorJob子协程失败不会相互影响// Dispatchers.Main.immediate 保证 launch 块立即在当前主线程执行若已在主线程returnsetTagIfAbsent(JOB_KEY,CloseableCoroutineScope(SupervisorJob()Dispatchers.Main.immediate))}// 包装一层 CloseableCoroutineScope 是为了让 ViewModel 在 onCleared() 时能关闭并取消 ScopeinternalclassCloseableCoroutineScope(context:CoroutineContext):Closeable,CoroutineScope{overridevalcoroutineContext:CoroutineContextcontextoverridefunclose(){// 当 ViewModel 被清除时调用此方法取消整个 Job 树// 所有未完成的子协程会收到取消信号避免内存泄漏coroutineContext[Job]?.cancel()}}要点viewModelScope与ViewModel生命周期绑定子协程之间通过SupervisorJob隔离失败ViewModel.onCleared()会触发CloseableCoroutineScope.close()从而取消所有协程。2. lifecycleScopeclassMainActivity:AppCompatActivity(){overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)lifecycleScope.launch{// 与 Activity / Fragment 生命周期绑定// 在 ON_DESTROY 时自动取消协程}}}源码分析// 伪代码逻辑展示核心机制internalclassLifecycleCoroutineScopeImpl(overridevallifecycle:Lifecycle,overridevalcoroutineContext:CoroutineContext):LifecycleCoroutineScope(),LifecycleEventObserver{init{// 关键注册生命周期观察者监听 DESTROY 事件lifecycle.addObserver(this)}overridefunonStateChanged(source:LifecycleOwner,event:Lifecycle.Event){if(eventLifecycle.Event.ON_DESTROY){// 当接收到 DESTROY 事件时自动取消协程// 避免在 Activity/Fragment 销毁后继续执行 UI 更新或耗时操作coroutineContext[Job]?.cancel()}}}valLifecycleOwner.lifecycleScope:LifecycleCoroutineScopeget(){// 每个 LifecycleOwner 只创建一次 Scope后续复用returnfindOrCreateScope()}要点lifecycleScope监听Lifecycle.Event.ON_DESTROY在页面销毁时自动取消协程防止空指针和内存泄漏。3. MainScope// 适用于不依赖 Activity/Fragment/ViewModel 的顶层协程管理场景privatevalscopeMainScope()scope.launch{// 在主线程执行的协程}// MainScope 本质上就是 SupervisorJob Dispatchers.MainpublicfunMainScope():CoroutineScopeContextScope(SupervisorJob()Dispatchers.Main)要点MainScope()创建了一个挂在主线程的顶层作用域需要手动调用scope.cancel()结束生命周期否则可能造成泄漏。4. GlobalScope// 不推荐直接使用协程生命周期跟随整个应用进程GlobalScope.launch{}DelicateCoroutinesApipublicobjectGlobalScope:CoroutineScope{// EmptyCoroutineContext 表示没有绑定 Job 和调度器// 使用时会自动创建 Job但无法从外部统一取消overridevalcoroutineContext:CoroutineContextget()EmptyCoroutineContext}要点GlobalScope是全局单例没有统一取消入口仅适合需要在整个应用生命周期内运行的后台任务通常应避免使用否则容易出现不可控的协程泄漏。总结作用域生命周期绑定是否需要手动取消推荐场景viewModelScopeViewModel否在 ViewModel 中发起网络请求、数据库操作lifecycleScopeActivity / Fragment否在 UI 层随页面创建/销毁的轻量任务MainScope()手动管理是类级别、不依赖生命周期组件的顶层协程GlobalScope应用进程否但无法统一取消原则上避免仅用于特殊全局后台任务一句话有生命周期就绑生命周期没生命周期再考虑MainScope尽量不用GlobalScope。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑