You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 31复制文件至私有存储抛出IllegalStateException解决方案

问题根因

崩溃抛出的java.lang.IllegalStateException: Only owner is able to interact with pending item是Android 10及以上版本系统对MediaStore待处理条目的强制权限拦截:
媒体文件写入MediaStore时如果设置了MediaStore.MediaColumns.IS_PENDING = 1标记,代表文件还处于写入流程、未正式落盘,此状态下只有最初创建这个媒体条目的应用有权限访问对应Uri,其他应用、甚至同应用在条目状态未更新完成时发起读取请求,都会直接触发该异常。
从堆栈信息看,异常触发点是子线程调用ContentResolver.openInputStream读取视频Uri的环节,说明执行复制操作时,目标视频对应的MediaStore条目还处于pending未完成状态,读取请求被系统直接拦截。

修复方案
  • 自有录制逻辑写入MediaStore的场景:视频文件完全写入完成后,先将对应条目的IS_PENDING标记更新为0,确认更新操作执行完毕,再触发私有存储复制逻辑,参考代码:
// videoUri为录制前向MediaStore插入条目时拿到的新视频Uri
ContentValues finishValues = new ContentValues();
finishValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
getContentResolver().update(videoUri, finishValues, null, null);
// update执行完成后再调用文件复制方法
  • 调用系统/第三方相机获取视频的场景:不要在收到结果回调的第一时间直接把Uri丢给线程池处理。相机应用写完文件后,MediaStore的状态更新存在几百毫秒的延迟,触发后台复制前先做可访问性校验,访问失败则短延迟重试:
boolean isFileReady = false;
try (ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(videoUri, "r")) {
    isFileReady = pfd != null;
} catch (Exception ignored) {}

if (isFileReady) {
    // 文件状态正常,提交到后台线程执行复制
    backgroundExecutor.execute(() -> copyFileToPrivateStorage(videoUri));
} else {
    // 延迟500ms重试,等待媒体库完成状态同步
    new Handler(Looper.getMainLooper()).postDelayed(() -> startCopyVideo(videoUri), 500);
}
  • 补上任务流程同步:不要在录制启动时就提前把Uri提交到后台任务队列,增加明确的状态标记位,保证流程顺序严格为「视频录制完成→MediaStore条目IS_PENDING标记置0→提交复制任务」,避免后台线程抢跑触发权限拦截。

内容的提问来源于stack exchange,提问作者Majd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 15:33:13