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

Android高版本从相册选图时文件找不到问题求助

问题分析与修复方案

Hey, let's break down why your code fails on API 21+ and how to fix it properly:

What's Going Wrong?

Your current code relies on MediaStore.Images.Media.DATA to get the file path of the selected image, but this approach breaks starting from API 21 for two key reasons:

  • API 21+ Content Uris: Many gallery apps (including the system gallery) start returning content:// style Uris instead of direct file paths. These Uris don't map to an accessible filesystem path you can use with new File().
  • Scoped Storage (API 29+): Android 10 introduced scoped storage, which restricts direct access to external storage files. The DATA field may even return null for some media items, since apps are no longer allowed to access arbitrary file paths.

Even with runtime permissions granted, you can't directly access the file via the path from DATA anymore on newer Android versions.

Fix 1: Use ContentResolver to Access the Image (Cross-API Compatible)

Instead of trying to get a file path, use ContentResolver.openInputStream() to read the image content directly from the Uri. This works for all API levels 14+, and avoids path-related issues entirely.

Here's how to update your onActivityResult code for the PICK_FOTO_ACTION case:

case PICK_FOTO_ACTION: {
    Uri imageUri = intent.getData();
    if (imageUri == null) {
        Toast.makeText(this, "Invalid image selected", Toast.LENGTH_LONG).show();
        break;
    }

    try {
        // Open an input stream to the image via ContentResolver
        InputStream inputStream = getContentResolver().openInputStream(imageUri);
        
        // Option 1: Convert to Bitmap directly for use in your contact entry
        Bitmap contactPhoto = BitmapFactory.decodeStream(inputStream);
        // Use the Bitmap for your contact UI or storage...

        // Option 2: Save the image to your app's private storage (if you need a file reference)
        File privatePhotoFile = new File(getFilesDir(), "contact_" + System.currentTimeMillis() + ".jpg");
        FileOutputStream outputStream = new FileOutputStream(privatePhotoFile);
        contactPhoto.compress(Bitmap.CompressFormat.JPEG, 90, outputStream);

        // Clean up streams to avoid leaks
        inputStream.close();
        outputStream.close();

        // Now you can use privatePhotoFile safely within your app
    } catch (IOException e) {
        e.printStackTrace();
        Toast.makeText(this, "Failed to access selected image", Toast.LENGTH_LONG).show();
    }
    break;
}

Fix 2: Update Permission Logic for Newer Android Versions

Starting from API 33 (Android 13), READ_EXTERNAL_STORAGE is deprecated. You should use READ_MEDIA_IMAGES instead to access gallery photos. Here's the updated permission check/request code:

public boolean filePermissionsRequired() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        return checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED;
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        return checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
    } else {
        return false;
    }
}

public boolean askForFilePermissions(PermissionRequestCompletionHandler completionHandler) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        permissionRequestCompletionHandler = completionHandler;
        boolean hasPermission = checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED;
        if (!hasPermission) {
            requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES}, 1);
            return true;
        }
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        permissionRequestCompletionHandler = completionHandler;
        boolean hasPermission = checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
        if (!hasPermission) {
            requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
            return true;
        }
    }
    permissionRequestCompletionHandler = null;
    return false;
}

Why Did This Work on API 14-20?

Before Android 5.0 (API 21), most gallery apps returned Uris that mapped directly to filesystem paths via the DATA column. Apps with WRITE_EXTERNAL_STORAGE permission could access these paths directly. But starting with API 21, the Android framework and third-party apps shifted to using content Uris for better security, breaking the old path-based approach.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:39:42