CoroutineScope(SupervisorJob())与GlobalScope的区别是什么?
答案很明确:GlobalScope完全不能替代与应用生命周期绑定的自定义CoroutineScope,核心差异体现在三个关键维度:
1. 生命周期无法绑定
GlobalScope的底层是顶层Job,它的生命周期不受应用进程控制——即使应用退到后台、即将被系统回收,GlobalScope启动的协程会一直执行到任务结束,这会导致不必要的资源消耗,甚至引发内存泄漏(比如协程持有Activity/Application的引用)。
而用SupervisorJob手动创建的自定义Scope,你可以在应用的销毁节点(比如Application的onTerminate,或自定义的退出逻辑)主动调用scope.cancel(),一次性终止所有子协程,完美贴合应用生命周期。
2. 异常处理逻辑不同
自定义Scope使用SupervisorJob时,子协程的异常是隔离的:单个子协程崩溃不会影响其他同级协程的运行。这对应用级场景至关重要——比如一个统计上报的协程失败,不该打断正在进行的网络请求协程。
但GlobalScope默认使用普通Job,一旦某个子协程抛出未捕获异常,整个GlobalScope下的所有协程都会被强制取消,风险极高。
3. 缺乏统一配置能力
GlobalScope默认使用Dispatchers.Default作为调度器,无法为应用内所有协程统一指定调度策略(比如默认用Dispatchers.Main处理UI相关任务,或Dispatchers.IO处理IO操作)。而自定义Scope可以在创建时就统一配置调度器、异常处理器等,让代码风格更一致,维护成本更低。
示例对比
正确的应用级Scope实现
// 全局单例的应用级CoroutineScope val AppCoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) // 启动与应用生命周期绑定的协程 AppCoroutineScope.launch { // 执行需要跟随应用生命周期的任务 } // 应用退出时调用,终止所有协程 AppCoroutineScope.cancel()
不推荐的GlobalScope用法
GlobalScope.launch { // 任务会不受控地运行,直到完成,即使应用已经退出 }
总结来说,GlobalScope是为无生命周期约束的全局任务设计的,而自定义带SupervisorJob的Scope才是适配应用生命周期的正确方案。
内容的提问来源于stack exchange,提问作者jane

