读写sd卡的权限时序图

读写sd卡的权限时序图理解
- 初始化不触发回调 :
initSqliteRWPermissionLauncher()仅注册申请器,全程不调用onSqliteRWPermissionResult; - 回调触发条件 :只有「调用
checkAndRequestSqliteRWPermission()发起申请 + 用户操作权限弹窗」后,才会回调onSqliteRWPermissionResult; - allGranted 来源 :由系统返回的
result解析生成(读 / 写权限都授权才为true),不是初始化时获取; - goToAppSetting 作用:仅作为「授权失败」后的兜底引导,需用户确认后再调用,不替代权限申请流程。
权限申请代码
/**
* 初始化:仅适配SQLite读写的SD卡权限申请器(重命名后)
* 仅初始化权限申请器,注册结果回调通道
*/
private void initSqliteRWPermissionLauncher() {
// 核心修改:sdCardPermissionLauncher 替代原 permissionLauncher
sdCardPermissionLauncher = registerForActivityResult(
new ActivityResultContracts.RequestMultiplePermissions(),
result -> {
// 检查读写权限是否都授权
boolean readGranted = result.getOrDefault(Manifest.permission.READ_EXTERNAL_STORAGE, false);
boolean writeGranted = result.getOrDefault(Manifest.permission.WRITE_EXTERNAL_STORAGE, false);
onSqliteRWPermissionResult(readGranted && writeGranted);
}
);
}
/**
* SQLite读写权限结果回调(子类重写)
* @param allGranted 读写权限是否都授权
*/
protected void onSqliteRWPermissionResult(boolean allGranted) {}
/**
* 检查并申请SD卡公共目录的SQLite读写权限(重命名后)
* 私有目录无需调用此方法!
* 1. 检查权限是否已授权;
* 2. 未授权则根据 Android 版本发起权限申请(Android 13 + 弹提示弹窗,低版本弹系统权限弹窗);
* 3. 授权结果通过 onSqliteRWPermissionResult() 回调
*
* 发起权限申请的核心入口:包含检查
*/
protected void checkAndRequestSqliteRWPermission() {
// 仅申请读写外部存储权限(SQLite是通用文件,无需媒体权限)
String[] permissions = new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
// 检查权限是否已授权
boolean readGranted = ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
boolean writeGranted = ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
if (readGranted && writeGranted) {
onSqliteRWPermissionResult(true);
return;
}
// Android 13+ 特殊处理:读写通用文件需引导到设置页
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
new MaterialAlertDialogBuilder(mContext)
.setTitle("权限申请")
.setMessage("需要读写SD卡中的SQLite数据库,请手动开启存储权限(跳转至设置页)")
.setPositiveButton("前往设置", (dialog, which) -> {
// 核心修改:调用重命名后的 sdCardPermissionLauncher
sdCardPermissionLauncher.launch(permissions);
})
.setNegativeButton("取消", (dialog, which) -> onSqliteRWPermissionResult(false))
.show();
} else {
// Android 12及以下:直接弹权限弹窗(调用重命名后的变量)
sdCardPermissionLauncher.launch(permissions);
}
}
/**
* 工具方法:检查SQLite读写权限是否已授权
* 遍历权限列表,调用 ContextCompat.checkSelfPermission 判断是否授权
*/
protected boolean isSqliteRWPermissionGranted() {
boolean readGranted = ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
boolean writeGranted = ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
return readGranted && writeGranted;
}
/**
* 可选:引导到应用设置页(权限拒绝时调用)
* 仅跳转到应用的系统设置页(用户需手动在设置页开启存储权限),无权限检查、无结果回调
*/
protected void goToAppSetting() {
android.content.Intent intent = new android.content.Intent();
intent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
android.net.Uri uri = android.net.Uri.fromParts("package", mContext.getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
详细的过程理解
初始化二行代码
boolean readGranted = result.getOrDefault(Manifest.permission.READ_EXTERNAL_STORAGE, false);
boolean writeGranted = result.getOrDefault(Manifest.permission.WRITE_EXTERNAL_STORAGE, false);
这两行代码是权限申请结果的解析逻辑,核心作用是从权限申请的返回结果中,精准获取「读取外部存储」和「写入外部存储」两个权限的授权状态,下面拆解每一部分的含义:
一、先理解核心 API:result 的本质
result 是 RequestMultiplePermissions(多权限申请)契约的返回值,类型为 Map<String, Boolean>:
- Key :权限常量(如
Manifest.permission.READ_EXTERNAL_STORAGE); - Value :
true= 用户授权,false= 用户拒绝。
二、逐行解析代码
1. boolean readGranted = result.getOrDefault(Manifest.permission.READ_EXTERNAL_STORAGE, false);
| 部分 | 含义 |
|---|---|
result.getOrDefault(...) |
Map 的安全取值方法:① 先根据 Key(权限常量)查找对应的 Value(授权状态);② 若 Key 不存在(比如申请时漏传该权限),则返回默认值 false; |
Manifest.permission.READ_EXTERNAL_STORAGE |
要查询的权限 Key:「读取外部存储」权限; |
false |
默认值:若未查询到该权限的授权结果,默认视为 "未授权"; |
| 整行作用 | 获取「读取外部存储」权限的授权状态,无结果时默认未授权,赋值给 readGranted; |
2. boolean writeGranted = result.getOrDefault(Manifest.permission.WRITE_EXTERNAL_STORAGE, false);
逻辑和上一行完全一致,只是查询的权限 Key 换成了「写入外部存储」(Manifest.permission.WRITE_EXTERNAL_STORAGE),最终获取该权限的授权状态并赋值给 writeGranted。
三、为什么要用 getOrDefault 而不是直接 get?
直接用 result.get(权限Key) 存在空指针风险!比如:若代码中不小心漏申请了某个权限,result 中就没有该 Key,result.get() 会返回 null,赋值给 boolean 类型变量时会抛出 NullPointerException。
而 getOrDefault 是 "安全取值":即使 Key 不存在,也会返回默认值 false,避免崩溃。
四、这两行代码的实际作用
结合后续逻辑 onSqliteRWPermissionResult(readGranted && writeGranted),这两行的最终目的是:只有「读取」和「写入」权限都被授权(两个变量都为 true),才判定为 "权限全部授权",否则判定为 "未授权"。
五、示例对比(安全 vs 不安全)
| 写法 | 安全性 | 场景测试 | 结果 |
|---|---|---|---|
result.getOrDefault(权限Key, false) |
安全 | 漏申请「写入」权限 | 返回 false,最终判定未授权,无崩溃 |
result.get(权限Key) |
不安全 | 漏申请「写入」权限 | 返回 null,赋值给 boolean 时崩溃 |
总结
这两行代码的核心是:安全解析多权限申请的返回结果,分别获取「读」「写」两个权限的授权状态,为后续判断 "是否全部授权" 提供依据,它是 "权限申请后的结果解析",而非 "提前检查授权状态"。
权限初始化及执行过程
initSqliteRWPermissionLauncher()→ 仅初始化权限申请器 (注册 "申请权限→接收结果" 的通道),不获取任何权限值;- 当调用
checkAndRequestSqliteRWPermission()发起权限申请后,用户操作(允许 / 拒绝)→ 系统返回权限结果 → 申请器解析出读写权限的value→ 回调给onSqliteRWPermissionResult; onSqliteRWPermissionResult中判断未授权 → 不能直接调用goToAppSetting(),需先弹窗提示用户,再让用户选择是否跳设置页(避免强制跳转);- 用户点击 "读写数据库" 按钮(click 事件)→ 先调用
checkAndRequestSqliteRWPermission()(检查权限,未授权则发起申请,已授权则直接读写)。
完整逻辑链路
页面创建 → 调用 initSqliteRWPermissionLauncher() → 准备好"权限申请工具"(无任何弹窗);
用户点击"读写数据库"按钮 → 调用 checkAndRequestSqliteRWPermission();
checkAndRequestSqliteRWPermission() 先检查权限: - 已授权 → 直接回调 onSqliteRWPermissionResult(true) → 执行读写数据库; - 未授权 → 发起权限申请(Android 13+弹提示弹窗,低版本弹系统权限弹窗);
用户操作权限弹窗(允许/拒绝)→ 工具解析结果(readGranted/writeGranted)→ 回调 onSqliteRWPermissionResult;
onSqliteRWPermissionResult 处理结果: - 授权成功 → 执行读写数据库; - 授权失败 → 弹窗提示用户 → 用户选择"前往设置"→ 调用 goToAppSetting() 跳设置页;
用户在设置页开启权限后返回 → onResume 中重新检查权限 → 已授权则自动执行读写(可选)。

精确理解初始化里面的**onSqliteRWPermissionResult 的 allGranted**
| 步骤 | 对应代码 | 通俗解释 | allGranted 状态 |
|---|---|---|---|
| 1. 初始化 | initSqliteRWPermissionLauncher() |
你去快递公司,领了空白快递单(注册申请器),但没填单、没寄件 | 无 allGranted,甚至这个参数还没诞生 |
| 2. 发起申请 | checkAndRequestSqliteRWPermission() |
你填好快递单(指定要申请的读写权限),交给快递员(调用 launch()) |
仍无 allGranted,等待收件人(用户)回复 |
| 3. 用户操作 | 系统弹权限弹窗,用户点「允许 / 拒绝」 | 收件人(用户)签收 / 拒收快递,快递员把结果写在回执上 | 回执上才有「是否全部签收」(allGranted)的结果 |
| 4. 回调 | onSqliteRWPermissionResult(allGranted) |
快递员把回执交给你,你拿到 allGranted 的值 |
allGranted 被赋值(true/false),进入回调逻辑 |
allGranted 的生成逻辑(代码层面)
allGranted 不是 "初始化时获取",而是权限申请有结果后,通过以下两步生成:
-
用户操作权限弹窗后,系统返回
result(Map<String, Boolean>,键是权限常量,值是授权状态); -
代码解析
result,计算出allGranted:java
运行
// 这是初始化时注册的回调逻辑,但只有发起申请后才会执行 result -> { boolean readGranted = result.getOrDefault(Manifest.permission.READ_EXTERNAL_STORAGE, false); boolean writeGranted = result.getOrDefault(Manifest.permission.WRITE_EXTERNAL_STORAGE, false); // 只有发起申请并得到结果,这行才会执行,allGranted 才会被赋值 onSqliteRWPermissionResult(readGranted && writeGranted); }
三、关键结论:allGranted 的两个核心特点
- 时序上 :
allGranted只有在「发起权限申请 + 用户操作」后才会产生,初始化阶段完全触及不到; - 来源上 :
allGranted来自「本次申请的用户操作结果」,不是「系统全局权限状态」(全局状态靠isSqliteRWPermissionGranted()检查); - 触发上 :
onSqliteRWPermissionResult是被动回调 ------ 你不用手动调用这个方法,只有发起申请并得到结果后,系统才会自动调用它,并把allGranted传进去。
四、反例验证:初始化时永远拿不到 allGranted
如果只执行初始化,不发起申请:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initSqliteRWPermissionLauncher(); // 仅初始化,不发起申请
// 此时 onSqliteRWPermissionResult 永远不会被调用,allGranted 不存在
}
只有调用 checkAndRequestSqliteRWPermission() 发起申请,且用户操作后,onSqliteRWPermissionResult 才会被触发,allGranted 才有值。
五、补充:容易混淆的 "提前检查" vs "回调结果"
你可能把「初始化前的权限检查」和「回调的 allGranted」搞混了:
- 提前检查(
isSqliteRWPermissionGranted()):是查「系统里是否已经授权」,结果不会触发onSqliteRWPermissionResult; - 回调的
allGranted:是查「本次申请用户是否授权」,只有发起申请后才会有。
比如:
- 用户之前已经授权过读写权限,你调用
checkAndRequestSqliteRWPermission()时,会直接触发onSqliteRWPermissionResult(true)(无需弹弹窗),但这依然是「发起申请后」的回调,不是「初始化时」的结果。
最终总结
onSqliteRWPermissionResult 的 allGranted 参数:
✅ 是「发起权限申请 + 用户操作」后才有的结果;
❌ 绝对不是初始化时获取的;
❌ 也不是主动去查的,而是系统自动回调给你的。
初始化只是 "准备工具",只有发起申请,工具才有 "干活的机会",才会产生 allGranted 并触发回调。