存储图片URI后跳转ThirdActivity触发SecurityException问题求助
问题分析与解决方案
问题根源
- 通过
ACTION_PICK获取的媒体URI仅拥有临时访问权限,权限仅在获取它的SecondActivity生命周期内有效,ThirdActivity直接读取该URI会触发权限异常。 - 你添加的
FLAG_GRANT_READ_URI_PERMISSION未绑定具体URI,且未将URI传递给ThirdActivity,权限授予逻辑无效。 - 直接持久化存储URI字符串不可靠,临时权限重启后会失效,无法跨生命周期或跨Activity复用。
解决方案一:跨Activity临时传递URI(适合单次跳转场景)
1. 修改SecondActivity跳转逻辑
读取存储的URI,传递给ThirdActivity并正确授予权限:
// SecondActivity.java Button showPickedButton = findViewById(R.id.showPickedButton); showPickedButton.setOnClickListener(view -> { String uriStr = ""; // 读取存储的URI字符串 try (BufferedReader reader = new BufferedReader(new InputStreamReader(openFileInput("uri"), StandardCharsets.UTF_8))) { uriStr = reader.readLine(); } catch (IOException e) { e.printStackTrace(); } if (!uriStr.isEmpty()) { Uri imageUri = Uri.parse(uriStr); Intent thirdIntent = new Intent(SecondActivity.this, ThirdActivity.class); // 将URI放入Intent传递 thirdIntent.setData(imageUri); // 授予ThirdActivity该URI的读取权限 thirdIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 兜底:显式授予权限,避免flag失效 grantUriPermission(getPackageName(), imageUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(thirdIntent); } });
2. 修改ThirdActivity读取逻辑
直接从Intent获取URI,无需读取文件:
// ThirdActivity.java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_third); LinearLayout imagesList = findViewById(R.id.imagesList); Uri imageUri = getIntent().getData(); if (imageUri != null) { ImageView imageView = new ImageView(this); imageView.setImageURI(imageUri); imageView.setAdjustViewBounds(true); imageView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); imagesList.addView(imageView); } }
解决方案二:持久化URI权限(适合长期复用场景)
如果需要保存URI并在后续启动、跨Activity时复用,需申请持久化权限,步骤如下:
1. 修改打开图库的Intent
用ACTION_OPEN_DOCUMENT替代ACTION_PICK,该Action支持持久权限申请:
// SecondActivity.java openGalleryButton.setOnClickListener(view -> { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.setType("image/*"); intent.addCategory(Intent.CATEGORY_OPENABLE); // 指定可打开的文件类型 activityResultLauncher.launch(intent); });
2. 修改ActivityResultLauncher逻辑,申请持久权限
获取URI后,调用takePersistableUriPermission获取持久访问权限:
ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { Intent data = result.getData(); if (data != null) { Uri imageUri = data.getData(); galleryImage.setImageURI(imageUri); if (imageUri != null) { // 获取Intent中的权限flag int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // 申请持久化权限 getContentResolver().takePersistableUriPermission(imageUri, takeFlags); } // 保存URI到文件 try { openFileOutput("uri", MODE_PRIVATE).write((imageUri + "\n").getBytes()); } catch (IOException e) { e.printStackTrace(); } } } });
3. ThirdActivity原逻辑无需修改(持久权限已生效)
此时ThirdActivity读取存储的URI字符串并加载图片,不会触发权限异常。
注意事项
- 持久化权限仅当用户主动选择文件时才能申请,无法自动获取;
- 若用户删除文件或在系统设置中撤销应用权限,持久权限会失效,需添加异常捕获逻辑;
ACTION_OPEN_DOCUMENT仅支持Android 4.4(API 19)及以上版本。
内容的提问来源于stack exchange,提问作者Alex Cai
相关产品推荐
相关产品推荐

