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

Android开发:如何从ActivityResultLauncher的Uri获取真实文件路径

问题描述

我正在开发一项拍照上传至服务器的功能,需以multipart/form-data格式向服务器发送数据,因此需要从ActivityResultLauncher获取的Uri创建文件。但该Uri为伪路径,由此创建的文件并不存在。请问如何从ActivityResultLauncher获取的Uri中获取真实路径?

更新:以下是我的代码

AndroidManifest.xml 配置

<provider
    android:authorities="com.tgddssss.projectcf.fileProvider"
    android:name="androidx.core.content.FileProvider"
    android:exported="false"
    android:grantUriPermissions="true">

    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths"/>

</provider>

@xml/file_paths 配置

<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
    name="camera_photos"
    path="."/>
</paths>

创建Uri的函数

fun createUri(): Uri {
    val currentTime = System.currentTimeMillis()
    val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault())
    val currentTimeString = dateFormat.format(Date(currentTime))
    val fileName = "photo_$currentTimeString.jpg"
    val file = File(requireActivity()?.applicationContext?.filesDir, fileName)
    return FileProvider.getUriForFile(
        requireActivity().applicationContext,
        "com.tgddssss.projectcf.fileProvider",
        file
    )
}

注册拍照Launcher的函数

fun registerPictureLauncher(imageUri: Uri?): ActivityResultLauncher<Uri> {
    return registerForActivityResult(
        ActivityResultContracts.TakePicture(),
        ActivityResultCallback {
            try {
                if (it) {
                    val file = File(imageUri.toString())
                    Log.d("TAG","${file.exists()}")
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    )
}

另外使用Permission Dispatcher进行权限检查...


解决方案

问题根源

你在registerPictureLauncher里直接用File(imageUri.toString())创建文件是错误的——imageUri是FileProvider生成的content://格式Uri,并非本地文件路径,所以这样生成的File必然不存在。

最优解决方式:复用已创建的File对象

其实你不需要从Uri反向获取真实路径,因为在createUri()方法里你已经明确创建了对应的本地File对象,只需要把这个File对象保存下来,在拍照成功后直接使用即可:

  1. 修改createUri(),返回File和Uri的组合
    把原来只返回Uri改成返回包含File和Uri的封装类,或者直接将File保存为成员变量:

    // 定义数据类封装文件信息
    data class CameraFileInfo(val file: File, val uri: Uri)
    
    fun createCameraFileInfo(): CameraFileInfo {
        val currentTime = System.currentTimeMillis()
        val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault())
        val currentTimeString = dateFormat.format(Date(currentTime))
        val fileName = "photo_$currentTimeString.jpg"
        val file = File(requireActivity().applicationContext.filesDir, fileName)
        val uri = FileProvider.getUriForFile(
            requireActivity().applicationContext,
            "com.tgddssss.projectcf.fileProvider",
            file
        )
        return CameraFileInfo(file, uri)
    }
    
  2. 注册Launcher时传入并复用File对象
    调用createCameraFileInfo()获取文件和Uri,在回调中直接使用已保存的File:

    // 获取拍照用的文件信息
    val cameraFileInfo = createCameraFileInfo()
    
    // 注册拍照Launcher
    val pictureLauncher = registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
        if (success) {
            // 直接使用预先创建好的File对象
            val targetFile = cameraFileInfo.file
            Log.d("TAG", "文件是否存在:${targetFile.exists()}")
            // 此处可直接用targetFile构建multipart/form-data请求上传
        }
    }
    
    // 启动拍照
    pictureLauncher.launch(cameraFileInfo.uri)
    

备用方案:从任意Uri生成可访问File

如果后续需要处理非自行生成的Uri(比如相册选择的图片),可以通过ContentResolver读取Uri对应的文件流,复制到应用私有目录生成可访问的File:

fun uriToFile(context: Context, uri: Uri): File? {
    return try {
        val inputStream = context.contentResolver.openInputStream(uri) ?: return null
        val tempFile = File(context.filesDir, "temp_${System.currentTimeMillis()}.jpg")
        FileOutputStream(tempFile).use { outputStream ->
            inputStream.copyTo(outputStream)
        }
        tempFile
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

注意事项

  • 拍照成功后,ActivityResultContracts.TakePicture()返回true即说明照片已写入你指定的File中,此时cameraFileInfo.file必然存在。
  • 上传完成后,可根据需求删除临时文件,避免占用存储空间。

内容的提问来源于stack exchange,提问作者Hùng Nguyễn Quý

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 04:25:00