请解释 Kotlin 协程中的 CoroutineScope 概念,并阐述在实际开发中应依据哪些原则或条件来选取恰当的作用域?
考察说明
考查对 Kotlin 协程作用域核心概念的理解及在不同场景下选择作用域的能力。
回答思路
- 【回答框架 1】CoroutineScope 是协程的上下文载体,它定义了协程的生命周期和结构,包含一个 Job 和调度器等元素。协程必须运行在一个作用域内,能通过其管理子协程,在作用域取消时统一取消内部所有协程。
- 【回答框架 2】选择作用域应遵循结构化并发原则:父协程等待所有子协程完成,取消时父协程同时取消所有子协程。因此优先使用可控生命周期的作用域,如通过 CoroutineScope(SupervisorJob() + Dispatchers.Main) 创建自定义作用域,并与界面或其他组件生命周期挂钩。
- 【回答框架 3】对于 UI 层,Android 中常用 lifecycleScope(对应 Lifecycle)或 viewModelScope(对应 ViewModel),它们会自动在生命周期结束时取消协程,避免泄漏。后台任务可使用 GlobalScope,但不推荐,因其生命周期与整个应用一致且无法取消,容易造成资源泄漏。
- 【回答框架 4】选用作用域时考虑因素:作用域与操作的生命周期绑定程度;操作是否需并发执行;是否需要隔离异常(使用 SupervisorJob 使子协程失败不影响兄弟协程);以及是否需要指定调度器。在多层结构中,子作用域应传递上下文遵循结构化并发。
- 【关键点 1】CoroutineScope 提供协程执行的上下文和生命周期管理。
- 【关键点 2】根据组件生命周期选择作用域,如 viewModelScope 与 UI 生命周期绑定。
- 【关键点 3】避免使用 GlobalScope,防止协程无法取消导致泄漏。
- 【关键点 4】结构化并发要求父子作用域协同管理,父取消则子取消。
- 【关键点 5】使用 SupervisorJob 实现异常隔离,应对独立任务。
- 【易错点 1】将 CoroutineScope 与 CoroutineContext 混淆,实际是组合封装。
- 【易错点 2】忽视结构化并发,调用 launch 时未在合适作用域内导致协程无法取消或泄漏。
- 【易错点 3】误用 GlobalScope 处理短期任务,违背生命周期约束。