题目1:问题定义与场景分析
Android 运行时权限模型自 6.0(API 23)引入后,应用需在运行时动态申请敏感权限。传统的权限请求基于 ActivityCompat.requestPermissions() + onRequestPermissionsResult() 回调,或使用 ActivityResultContracts.RequestMultiplePermissions 的 Launcher 方式。这些方案在复杂逻辑(多重权限链、条件驳回、权限降级回退)下极易导致代码碎片化、生命周期耦合以及测试困难。
本课程专注于 协程异步权限请求流程设计,利用 Kotlin 协程的结构化并发能力,将权限请求从回调驱动的乱流转换为声明式挂起函数,从而解决传统实现中的核心痛点。
常见痛点
| 痛点 | 描述 | 传统写法示例 |
|---|---|---|
| 回调地狱 | 嵌套多层回调,逻辑散落在不同生命周期回调中,可读性差 | |
| 生命周期泄漏 | 权限结果回调时 Activity 可能已销毁,导致 IllegalStateException 或内存泄漏 | |
| 多权限组合复杂 | 一次性请求多个权限时,必须等待所有结果返回后再合成状态,逻辑判断臃肿 | |
| 用户拒绝后难以优雅降级 | 用户点击“拒绝”后,应用需要判断是否应该弹窗解释;若再次拒绝则永久拒绝,状态机复杂 | |
| 单元测试困难 | 回调依赖 Activity/Fragment 实例,难以使用纯单元测试 mock 权限结果 | |
关键认识:以上痛点的本质是“异步控制流与 Android 生命周期的交错耦合”。协程通过
suspend 函数、CoroutineScope 和 Dispatchers.Main 提供了一种线性挂起的能力,天然适合将权限请求封装为可恢复的点,从而消除回调嵌套。设计目标
基于痛点,协程异步权限请求流程应达成以下目标:
- 结构化并发 —— 每个权限请求绑定到指定
CoroutineScope(如viewModelScope或lifecycleScope),Activity 销毁时自动取消,避免泄漏。 - 声明式 API —— 用一个挂起函数表达“请求权限并等待结果”,调用方不再接触回调。
- 生命周期安全 —— 内部自动处理
isFinishing、onSaveInstanceState等边界,保证结果安全分发。 - 支持多权限组合 —— 提供
all(全部授权) /any(任一授权)等组合语义,减少条件判断。 - 可测试性 —— 权限请求逻辑可被注入 mock 权限检查器,支持单元测试和集成测试。
- 用户友好 —— 内置“是否应弹解释对话框”判断和“前往设置”跳转封装,减少样板代码。
以下 SVG 图展示了传统回调式权限请求与协程异步权限请求的流程对比,以及设计目标如何解决痛点。
注意:协程并非自动消除所有权限复杂度。若不当处理
withContext(Dispatchers.Main) 或跨协程取消,仍可能出现“权限已挂起但界面已关闭”的异常。后续章节将逐一讲解如何用 suspendCancellableCoroutine 实现安全的一步请求。