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

Android14部分存储权限下如何正确获取用户选择的图片?

Android 14 部分存储权限下无法捕获用户选中图片的解决方案

问题描述

开发支持图库选择照片/视频的Android应用时,在Android 14(API 34)的部分存储权限机制下遇到异常:用户选择「SELECT PHOTOS AND VIDEOS」授予READ_MEDIA_VISUAL_USER_SELECTED权限后,系统自动弹出的媒体选择器选中的图片无法被正确获取,自定义的selectFirstImageFromMedia()方法返回随机旧图而非用户本次选中的内容。

错误原因

核心逻辑错误:当用户授予部分权限时,系统自动启动的媒体选择器,其选中结果不会通过MediaStore查询返回,而是必须通过标准的ActivityResult回调接收。你当前尝试用MediaStore查询获取选中内容的方式,在部分权限模式下只能访问用户之前授权过的媒体文件,和本次选择完全无关。

解决方案

统一使用ActivityResultContracts.PickVisualMedia契约处理所有权限场景的媒体选择,移除错误的MediaStore查询逻辑:

1. 修正权限检查逻辑

public boolean checkPermission(String permission) {
    int statusCode = ContextCompat.checkSelfPermission(this, permission);
    return statusCode == PackageManager.PERMISSION_GRANTED;
}

// 权限检查触发逻辑
int sdk = Build.VERSION.SDK_INT;
if (sdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
    // 只要有任一权限就启动媒体选择器
    if (checkPermission(Manifest.permission.READ_MEDIA_IMAGES) || checkPermission(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)) {
        selectImage();
    } else {
        permissionLauncher.launch(new String[]{
                Manifest.permission.READ_MEDIA_IMAGES,
                Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
        });
    }
}

2. 修正权限回调处理

移除selectFirstImageFromMedia()的调用,直接启动媒体选择器:

permissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> {
    boolean hasAnyPermission = false;
    int sdk = Build.VERSION.SDK_INT;
    
    if (sdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
        hasAnyPermission = checkPermission(Manifest.permission.READ_MEDIA_IMAGES) || checkPermission(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED);
    }
    
    if (hasAnyPermission) {
        selectImage();
    } else {
        Toast.makeText(this, "应用需要权限才能选择图片", Toast.LENGTH_SHORT).show();
    }
});

3. 保留原有的媒体选择与结果回调逻辑

selectImage()和pickMedia回调无需修改,PickVisualMedia契约会自动适配权限场景:

public void selectImage() {
    int sdk = Build.VERSION.SDK_INT;
    if (sdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
        pickMedia.launch(new PickVisualMediaRequest.Builder()
                .setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE)
                .build());
    } else {
        Intent picIntent = new Intent(Intent.ACTION_GET_CONTENT, null);
        picIntent.setType("image/*");
        picIntent.putExtra("return_data", true);
        startActivityForResult.launch(picIntent);
    }
}

// 接收Android 14+的媒体选择结果
pickMedia = registerForActivityResult(new ActivityResultContracts.PickVisualMedia(), uri -> {
    if (uri != null) {
        setImageInView(uri);
    } else {
        Toast.makeText(getApplicationContext(), "已取消选择", Toast.LENGTH_SHORT).show();
    }
});

4. 移除无用的selectFirstImageFromMedia()方法

该方法在部分权限场景下无法获取正确结果,直接删除即可。

原理说明

  • 当用户授予READ_MEDIA_VISUAL_USER_SELECTED权限时,系统自动弹出的选择器是权限授权流程的一部分,其选中结果只能通过ActivityResult回调接收,无法通过MediaStore查询获取
  • PickVisualMedia契约已经适配了Android 14的部分权限机制,无论用户授予全部权限还是部分权限,都会正确返回用户选中的媒体URI

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:14:50