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

如何读取应用创建的MediaStore URI对应图片?解决文件找不到异常

问题解决:MediaStore插入后Uri缺失content://前缀导致读取失败

你遇到的FileNotFoundException本质是返回的Uri格式不合法——正常情况下contentResolver.insert()返回的Uri应该带有content://前缀,出现无前缀的情况大概率是代码冗余操作或极端系统环境导致的异常,以下是当前通用的标准实现方案:

一、修正MediaStore插入逻辑

优化addToMediaStore()方法,去除冗余配置,确保Uri生成和状态流转的正确性:

private val filenameDateFormat = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")

fun addToMediaStore(): Uri? {
    val filename = "image_${Clock.System.now().format(filenameDateFormat)}.jpg"
    val contentValues = ContentValues().apply {
        put(MediaStore.Images.Media.IS_PENDING, 1) // 锁定条目,避免媒体扫描干扰
        put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
        put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") // 标准MIME类型,不要用image/jpg
        put(
            MediaStore.MediaColumns.RELATIVE_PATH, 
            "${Environment.DIRECTORY_PICTURES}/MyApplication"
        )
    }

    var mediaStoreUri: Uri? = null
    try {
        mediaStoreUri = contentResolver.insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            contentValues
        )

        mediaStoreUri?.let { uri ->
            copyUri(tempUri, uri) // 执行文件复制
            // 解锁条目,允许媒体扫描器识别
            contentValues.clear()
            contentValues.put(MediaStore.Images.Media.IS_PENDING, 0)
            contentResolver.update(uri, contentValues, null, null)
        }
    } catch (e: Exception) {
        // 失败时清理无效条目
        mediaStoreUri?.let { contentResolver.delete(it, null, null) }
        mediaStoreUri = null
        e.printStackTrace()
    }
    return mediaStoreUri
}

二、实现安全的Uri复制方法

copyUri是核心环节,必须确保流的完整读写:

private fun copyUri(sourceUri: Uri, destUri: Uri) {
    contentResolver.openInputStream(sourceUri)?.use { inputStream ->
        contentResolver.openOutputStream(destUri)?.use { outputStream ->
            inputStream.copyTo(outputStream)
            outputStream.flush() // 强制刷新,确保数据写入完成
        } ?: throw IOException("无法打开目标Uri输出流")
    } ?: throw IOException("无法打开源Uri输入流")
}

三、读取Bitmap时的兼容处理

读取前强制校验Uri格式,避免非法格式导致崩溃:

fun loadBitmapFromMediaStore(uri: Uri?): Bitmap? {
    uri ?: return null
    // 极端情况补全content://前缀
    val validUri = if (!uri.toString().startsWith("content://")) {
        Uri.parse("content://$uri")
    } else {
        uri
    }

    return try {
        contentResolver.openInputStream(validUri)?.use { stream ->
            BitmapFactory.decodeStream(stream)
        }
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

关键注意事项

  • MIME类型规范:必须使用image/jpeg而非image/jpg,部分系统对非标准MIME类型兼容性差。
  • IS_PENDING状态:写入前锁定、写入后解锁,避免媒体扫描器在文件写入过程中读取不完整数据。
  • 异常清理:插入或写入失败时,务必删除已创建的空MediaStore条目,避免产生无效记录。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 10:53:15