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

在RecyclerView Adapter中加载URI图片遇权限拒绝问题求助

问题:从URI加载图片在Activity正常,RecyclerView.Adapter中出现权限拒绝
  • 场景:通过用户选择的图片URI,在Activity中加载正常,但在Fragment关联的RecyclerView.Adapter的onBindViewHolder方法中加载时抛出权限拒绝错误
  • 补充:该URI在与选择图片的Activity无关的其他Activity中也能正常加载

错误信息

java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{e8f7e7f 20114:my.package.name/u0a290} (pid=20114, uid=10290) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs

当前相关代码

图片加载代码

user_image = findViewById(R.id.user_image);
String path = sharedPreferences.getString("imagePath", "default");
if (path.equals("default")) {
    user_image.setImageResource(R.drawable.profile);
} else {
    user_image.setImageURI(Uri.parse(path));
}

图片选择及路径保存代码

Intent i = new Intent();
i.setType("image/*");
i.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(i, "Select Picture"), IMAGE_REQUEST_CODE);

OnActivityResult代码

Uri selectedImageUri = data.getData();
SharedPreferences sharedPreferences = requireActivity().getSharedPreferences("USERDATA", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();

if (selectedImageUri != null) {
    image_view.setImageURI(selectedImageUri);
    imagePath = selectedImageUri.toString();
    editor.putString("imagePath", imagePath);
    editor.apply();
 }

原因及解决方案

核心原因

使用ACTION_GET_CONTENT获取的URI仅拥有临时访问权限,该权限仅在发起请求的Activity生命周期内有效。后续在Adapter等其他组件中使用该URI时,临时权限已失效,因此触发权限拒绝错误。你提到的其他Activity能正常加载,只是系统权限缓存未清除的偶然情况,并非可靠行为。

解决方法

方法1:改用ACTION_OPEN_DOCUMENT获取持久化权限

这是Android官方推荐的方案,通过ACTION_OPEN_DOCUMENT获取URI并申请持久化权限,确保后续任何组件都能正常访问:

// 修改图片选择Intent
Intent i = new Intent(Intent.ACTION_OPEN_DOCUMENT);
i.setType("image/*");
i.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(i, "Select Picture"), IMAGE_REQUEST_CODE);

// 修改OnActivityResult代码,添加权限持久化逻辑
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == IMAGE_REQUEST_CODE && resultCode == RESULT_OK && data != null) {
        Uri selectedImageUri = data.getData();
        if (selectedImageUri != null) {
            // 申请持久化读写权限
            final int takeFlags = data.getFlags()
                    & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            requireActivity().getContentResolver().takePersistableUriPermission(selectedImageUri, takeFlags);
            
            // 保存URI到SharedPreferences
            SharedPreferences sharedPreferences = requireActivity().getSharedPreferences("USERDATA", MODE_PRIVATE);
            SharedPreferences.Editor editor = sharedPreferences.edit();
            editor.putString("imagePath", selectedImageUri.toString());
            editor.apply();
            
            image_view.setImageURI(selectedImageUri);
        }
    }
}

方法2:将图片复制到应用私有目录后保存路径

如果不需要保留原图位置,可以将选中的图片复制到应用私有存储目录,后续通过私有路径加载图片:

// 修改OnActivityResult代码,复制图片到私有目录
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == IMAGE_REQUEST_CODE && resultCode == RESULT_OK && data != null) {
        Uri selectedImageUri = data.getData();
        if (selectedImageUri != null) {
            try {
                // 读取选中的图片流
                InputStream inputStream = requireActivity().getContentResolver().openInputStream(selectedImageUri);
                // 创建应用私有目录下的文件
                File privateDir = requireActivity().getFilesDir();
                File imageFile = new File(privateDir, "user_profile.jpg");
                // 将图片写入私有文件
                FileOutputStream outputStream = new FileOutputStream(imageFile);
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                inputStream.close();
                outputStream.close();
                
                // 保存私有路径到SharedPreferences
                SharedPreferences sharedPreferences = requireActivity().getSharedPreferences("USERDATA", MODE_PRIVATE);
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putString("imagePath", imageFile.getAbsolutePath());
                editor.apply();
                
                image_view.setImageURI(selectedImageUri);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

// 修改图片加载代码,通过私有路径加载
user_image = findViewById(R.id.user_image);
String path = sharedPreferences.getString("imagePath", "default");
if (path.equals("default")) {
    user_image.setImageResource(R.drawable.profile);
} else {
    // 推荐使用Glide/Picasso等图片加载库避免OOM
    // Glide.with(context).load(new File(path)).into(user_image);
    Bitmap bitmap = BitmapFactory.decodeFile(path);
    user_image.setImageBitmap(bitmap);
}

注意事项

  • 方法1无需占用额外存储,适合保留原图位置的场景
  • 方法2需要处理文件IO异常,适合需要对图片编辑或二次处理的场景
  • 禁止直接保存ACTION_GET_CONTENT获取的URI并在后续组件中使用,临时权限不可靠

内容的提问来源于stack exchange,提问作者Syed Irfan Hussaini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 19:01:20