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

Android 10中从Bitmap获取URI的方法求助

解决Android 10中MediaStore URI获取的适配问题

我来帮你搞定这个Android 10(API 29)的适配痛点——这本质是分区存储机制引入后带来的API兼容问题,咱们一步步拆解解决:

先解决编译错误:无法识别Q、RELATIVE_PATH等常量

你遇到的无法解析Q、RELATIVE_PATH、IS_PENDING问题,90%是因为项目的编译SDK版本没升到29及以上。这些API是Android 10才新增的,低版本编译SDK根本识别不了。

打开Module级别的build.gradle,把编译和目标SDK版本调整成这样:

android {
    compileSdkVersion 29 // 或更高版本,比如33、34都可以
    defaultConfig {
        targetSdkVersion 29 // 建议和compileSdkVersion保持一致
        // ...其他原有配置
    }
}

同步项目后,那些编译错误应该就消失了。

替换废弃的insertImage方法,适配Android 10+

你原来用的MediaStore.Images.Media.insertImage在Android 10及以上已经被标记为@Deprecated,而且会触发分区存储的限制,所以必须改用ContentValues+ContentResolver的方式来插入文件并获取URI。

下面是完整的Bitmap存储并获取URI的适配代码,兼容Android 10及以下:

private Uri saveBitmapToMediaStore(Context context, Bitmap bitmap, String mimeType) {
    ContentValues contentValues = new ContentValues();
    // 生成唯一文件名,避免重复
    String fileName = System.currentTimeMillis() + ".jpg";
    contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
    contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);

    Uri uri = null;
    ContentResolver resolver = context.getContentResolver();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // Android 10+:使用分区存储的相对路径,比如存在Pictures下的自定义文件夹
        String relativePath = Environment.DIRECTORY_PICTURES + "/YourAppVideoThumb";
        contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativePath);
        // 标记文件为"待处理",防止其他应用在写入完成前访问
        contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);

        // 插入到MediaStore的图片集合中,获取临时URI
        uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
    } else {
        // Android 9及以下:用传统文件存储+MediaScanner扫描的方式
        String storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath();
        String savePath = storageDir + "/YourAppVideoThumb/" + fileName;
        File saveFile = new File(savePath);
        
        // 创建文件夹(如果不存在)
        if (!saveFile.getParentFile().exists()) {
            saveFile.getParentFile().mkdirs();
        }

        // 把Bitmap写入文件
        try (FileOutputStream fos = new FileOutputStream(saveFile)) {
            bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

        // 扫描文件到MediaStore,生成URI
        MediaScannerConnection.scanFile(context, new String[]{savePath}, new String[]{mimeType}, (path, scannedUri) -> {
            uri = scannedUri;
        });
        // 注意:这里是异步操作,如果需要同步返回,建议加个短暂等待或者改用回调逻辑
    }

    // Android 10+:将Bitmap写入到刚才获取的URI对应的流中
    if (uri != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        try (OutputStream outputStream = resolver.openOutputStream(uri)) {
            bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream);
            outputStream.flush();

            // 写入完成后,取消"待处理"标记,允许其他应用访问
            ContentValues updateValues = new ContentValues();
            updateValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
            resolver.update(uri, updateValues, null, null);
        } catch (IOException e) {
            e.printStackTrace();
            // 写入失败,删除刚才插入的空记录
            resolver.delete(uri, null, null);
            uri = null;
        }
    }

    return uri;
}

关键知识点说明

  1. 分区存储规则:Android 10+不允许直接操作外部存储的文件路径,必须通过MediaStore API来读写公共目录下的文件
  2. IS_PENDING的作用:插入时设为1,避免其他应用在文件写入完成前读取到空文件;写入完成后设为0,开放访问权限
  3. 权限适配:Android 10+不需要申请WRITE_EXTERNAL_STORAGE权限(分区存储默认允许写入公共目录的指定位置);如果你的targetSdkVersion是28及以下,仍需正常申请存储权限

如果你是要获取视频文件的URI(而不是Bitmap缩略图),只需要把代码中的MediaStore.Images.Media.EXTERNAL_CONTENT_URI换成MediaStore.Video.Media.EXTERNAL_CONTENT_URI,MIME_TYPE换成对应视频类型(比如video/mp4),相对路径换成Environment.DIRECTORY_MOVIES + "/YourAppVideo"即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 22:12:50