news 2026/10/8 13:13:25

B11_ContentProvider与内容访问

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
B11_ContentProvider与内容访问

Android 基础补强 B11|ContentProvider:从一个 URI 读懂跨应用内容访问

发布摘要:读取用户选中文档的名称和大小,区分 ContentResolver、Cursor、内容 URI、临时访问与持久授权。标签:ContentProvider、ContentResolver、URI、Android。

系统文件选择器返回了content://开头的地址,有人第一反应是查“怎样转成真实文件路径”。这常常把问题引向错误方向:内容可能来自云盘、媒体库或另一个应用,根本没有对我们公开的本地路径。正确入口是让提供者按自己的协议交付元数据或字节流。

本篇对应《第一行代码》第 8 章,补强 D19 文件分享背后的基础。D19 负责向外提供文件,这里研究客户端怎样读取已授权内容,以及为什么保存 URI 字符串不代表永久拥有访问权。代码为未编译运行的教学片段。

一、把四个对象放在一次查询里

ContentProvider 是提供数据的组件;ContentResolver 是客户端访问入口;内容 URI 标识某项或某类内容;Cursor 是表格式查询结果。提供者底层可以使用数据库、文件或其他来源,客户端不应该绕过它去猜内部实现。

URI 的 authority 用于定位提供者,path 由该提供者定义含义,不能一律理解成文件夹。查询中的 projection 表示需要哪些列,selection 与参数表达筛选条件,但不是所有提供者都支持任意 SQL 功能。使用公开 Contract 常量比猜列名可靠。ContentProvider 基础

第一步用系统文档选择器拿到用户选择的 URI;第二步只查询名称和大小;第三步按需要打开输入流;第四步明确内容是否需要跨重启再次读取。将授权和读取分步观察,可以避免把 SecurityException 都误判为路径错误。

二、查询元数据并正确关闭 Cursor

以下函数接受已经取得读取授权的可打开文档 URI。导入全部列出,需要协程核心依赖。函数从挂起调用点执行,查询放到 IO 上;返回 null 表示未取得一行元数据,不等于文件内容为空。

importandroid.content.ContentResolverimportandroid.net.Uriimportandroid.provider.OpenableColumnsimportkotlinx.coroutines.Dispatchersimportkotlinx.coroutines.withContextdataclassDocumentMeta(valname:String?,valsizeBytes:Long?)suspendfunreadDocumentMeta(resolver:ContentResolver,uri:Uri):DocumentMeta?=withContext(Dispatchers.IO){resolver.query(uri,arrayOf(OpenableColumns.DISPLAY_NAME,OpenableColumns.SIZE),null,null,null)?.use{cursor->if(!cursor.moveToFirst())return@usenullvalnameColumn=cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)valsizeColumn=cursor.getColumnIndex(OpenableColumns.SIZE)DocumentMeta(name=if(nameColumn>=0&&!cursor.isNull(nameColumn))cursor.getString(nameColumn)elsenull,sizeBytes=if(sizeColumn>=0&&!cursor.isNull(sizeColumn))cursor.getLong(sizeColumn)elsenull)}}

大小未知与零字节不同。云端提供者可能尚不能返回长度,UI 应显示“大小未知”,不要凭空显示零。文件名也不能直接用作本地写入路径;若要复制,应生成应用自己的安全文件名,并保持目录边界。

Cursor 使用 use 保证正常和异常路径都关闭。真正读取内容时也应对openInputStream返回的流使用 use,边读边处理,给导入大小设合理上限。不要为了预览名称就把整个大文件读入内存。这里的 withContext 只避免查询阻塞主线程,不承诺底层跨进程查询在协程取消后立即终止;复杂长查询可以进一步使用 CancellationSignal。

三、临时授权与持久授权要分开

ACTION_OPEN_DOCUMENT 适合需要后续继续访问的文档。返回 Intent 中实际授予的读写标志应被检查,只有确实获得允许持久化的授权时,才调用 takePersistableUriPermission,且仅申请需要且已授予的访问模式。文档选择与持久权限

如果使用 StartActivityForResult 合约接收原始结果,可以先从data.flags取出读写位,再检查持久授权位。只读功能不应顺手保留写权限。持久权限取得成功后再保存 URI 字符串;失败则说明当前文件只能按临时访问处理,或者让用户重新选择,不能假装已经永久保存。

即便持久授权成功,用户移动、删除文档、提供者移除或主动撤销授权仍可能导致读取失败。重新打开时要处理无权限与找不到内容,提供重新选择入口。记录授权状态可以帮助排错,但每次实际访问仍是最后判断依据。

ACTION_GET_CONTENT 常用于一次性取得内容,不能照搬所有 OpenDocument 的持久化假设。也不要拿 FileProvider 临时分享 URI 调用持久授权 API,指望把它升级成永久权限。

四、反过来看自定义 Provider 的边界

书中的自定义 Provider 帮助理解 URI 匹配、查询和增删改。练习可以只暴露收藏编号与标题,明确允许哪些路径、哪些列、哪些操作。不要把所有传入字符串原样拼进 SQL;值通过选择参数绑定,排序字段等无法作为值绑定的位置采用白名单。

Provider 可能被并发访问,不能假定所有调用都在同一工作线程。对外暴露还需要设计 exported、读写权限及 URI 临时授权策略。把 exported 改成 true 并不意味着访问已安全,更不意味着可以忽略调用者权限。内部 Repository 没有跨应用访问需求时,也无需为“看起来完整”额外创建 Provider。

五、故障实验与预期

选择一个普通文本文件、一个大小未知的远端文档和一个空文件,比较显示。预期未知与零能区分,查询结束 Cursor 被关闭。远端文档是否可用取决于实际设备安装的提供者,不能虚构测试结果。

第二组保存 URI 字符串但不保留持久授权,重启设备后再次读取,观察结果;然后使用确实支持持久授权的 OpenDocument 流程对照。预期后者在内容仍存在且权限未撤销时可以继续访问,不应把一次成功扩大为永久保证。

第三组选择后删除原文件,预期应用提示重新选择,已有收藏数据保持完整。这样能验证文件入口失败没有破坏业务数据库。

六、原创面试问答与追问

可连接题库四大组件与权限申请。以下为原创练习。

问:content URI 为什么不是普通文件路径?答:它描述提供者的内容标识,真实存储由提供者决定。追问:怎样读取?使用 ContentResolver 和该提供者支持的操作。

问:把 URI 存进数据库就能下次读取吗?答:还取决于权限寿命和内容是否存在。追问:持久授权会保证文件永不消失吗?不会,它只保留允许的访问权限。

问:查询结果为空和查询抛异常一样吗?答:不一样,前者可能只是没有匹配记录,后者可能是权限或提供者故障。追问:UI 为什么要分开?可恢复动作不同,不能都显示“没有文件”。

七、练习与验收

建议在 D19 后增加一次六十到九十分钟基础练习:做文档信息卡,支持选择、名称、未知大小、重新打开与重新选择。书中 Provider 示例读完后,再画客户端、Resolver、Provider 和存储四层关系。

验收时闭卷说明一次 URI 访问经过哪些检查,并提交查询资源释放、授权丢失和文件删除三类记录。只实现了读取元数据,就在博客中写清范围,不宣称已经实现任意文件管理器。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 13:11:36

高密最新招聘信息正规机构

在高密找工作,很多人会先搜“高密最新招聘信息”“正规机构”。 但招聘信息渠道多,真假混杂,求职者和招工企业都需要多留个心眼。想及时看本地岗位,可以关注高密招聘网。 它主要面向高密本地求职者和招工企业,提供岗位…

作者头像 李华
网站建设 2026/10/8 13:09:31

宏碁电脑故障排查与日常维护全攻略(2026年10月更新)

更新时间:2026年10月适用设备:宏碁全系列笔记本、轻薄本、游戏本、二合一平板设备 一、前言 宏碁电脑性能均衡、机身轻薄,广泛用于办公、学习、影音与游戏场景。长期高频使用,常会出现卡顿、续航衰减、散热降频、蓝屏、无法开机、…

作者头像 李华