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

Android中SQLite存图片URI后加载触发SecurityException的解决方法

嘿,这个问题我太熟悉了!你碰到的SecurityException本质是个权限生命周期的坑——从相册拿到的图片URI只有临时访问权限,存进SQLite之后再取出来用,之前的临时授权早就过期了,系统自然会阻止你访问资源。而且还有个隐形隐患:如果用户后续删除了相册里的这张图,你存在数据库里的URI直接就失效了。

下面给你两种靠谱的解决方案,优先推荐第一种:

解决方案1:复制图片到应用私有目录,存储私有路径

这是最稳妥的方案,把选中的图片复制到应用自己的私有存储区域,这样你完全掌控文件的生命周期,再也不会有权限问题。

步骤1:在onActivityResult里复制图片到私有目录

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    // 替换成你自己的图片选择请求码
    if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {
        Uri imageUri = data.getData();
        if (imageUri != null) {
            try {
                // 打开相册图片的输入流
                InputStream inputStream = getContentResolver().openInputStream(imageUri);
                // 在应用内部存储创建唯一命名的图片文件(避免重名)
                File outputFile = new File(getFilesDir(), "prod_img_" + System.currentTimeMillis() + ".png");
                // 复制文件到私有目录
                FileOutputStream outputStream = new FileOutputStream(outputFile);
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                // 记得关闭流
                inputStream.close();
                outputStream.close();
                // 把私有目录的文件路径存进SQLite
                String imagePath = outputFile.getAbsolutePath();
                saveImagePathToDB(imagePath); // 替换成你的数据库存储方法
            } catch (IOException e) {
                e.printStackTrace();
                // 这里可以加个Toast提示用户图片保存失败
            }
        }
    }
}

步骤2:从数据库取路径加载图片

// 从数据库取出存储的路径
String savedImagePath = getImagePathFromDB(); // 替换成你的数据库查询方法
// 加载到ImageView
File imageFile = new File(savedImagePath);
if (imageFile.exists()) {
    // 推荐用Glide/Picasso这类图片库,自动处理缓存和内存
    // Glide.with(this).load(imageFile).into(yourImageView);
    
    // 要是不想用第三方库,也可以用BitmapFactory
    Bitmap bitmap = BitmapFactory.decodeFile(savedImagePath);
    yourImageView.setImageBitmap(bitmap);
}
解决方案2:申请持久化URI权限(仅Android 4.4+)

如果你不想复制文件占用额外存储,可以申请对相册图片URI的持久化访问权限,这样即使应用重启也能访问。但要注意:用户删除原图片后,URI还是会失效,而且只支持Android 19及以上版本。

步骤1:在onActivityResult中获取持久化权限

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {
        Uri imageUri = data.getData();
        if (imageUri != null) {
            // 提取临时权限标识,转为持久化权限
            int takeFlags = data.getFlags() & 
                (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            getContentResolver().takePersistableUriPermission(imageUri, takeFlags);
            // 把URI字符串存进SQLite
            saveImageUriToDB(imageUri.toString()); // 替换成你的数据库存储方法
        }
    }
}

步骤2:取出URI加载图片

// 从数据库取出URI字符串,解析为Uri对象
String savedUriStr = getImageUriFromDB(); // 替换成你的数据库查询方法
Uri savedUri = Uri.parse(savedUriStr);
// 直接加载到ImageView
yourImageView.setImageURI(savedUri);
// 同样推荐用图片库:Glide.with(this).load(savedUri).into(yourImageView);
小提示
  • 优先选方案1:完全独立控制图片,不受用户操作相册的影响,兼容性覆盖所有Android版本。
  • 尽量用第三方图片加载库(比如Glide),它们会自动处理图片压缩、内存缓存、异常情况,比自己写BitmapFactory靠谱多了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:49:39