Android Kotlin视频预览及Firebase上传时出现String转Uri异常
问题根因
抛出ClassCastException的核心原因有两个:
- 你声明
file为Any类型,没有做明确的类型约束,后续上传Firebase的逻辑里大概率直接将存储的字符串路径强转为Uri类型,触发类型转换错误。 - 你实现的
getRealPathFromUri方法本身存在兼容性缺陷:方法内使用MediaStore.Images.Media.DATA查询视频资源(该字段是图片资源的查询列,查询视频无法拿到正确结果),且Android 10及以上版本已经禁止应用通过MediaStore直接获取共享文件的真实本地路径,该方法在新系统上拿到的结果完全无效,属于多余逻辑。
修复方案
你完全不需要获取视频的本地真实路径,系统返回的data.data本身就是授权可访问的视频Uri,VideoView预览、Firebase上传都可以直接基于这个Uri实现,不需要绕路转文件路径。
- 替换模糊类型的变量声明,明确指定为Uri类型,避免隐式类型转换问题:
private lateinit var pickedVideoUri: Uri
- 直接删除无效的
getRealPathFromUri方法,该方法在targetSdkVersion 29及以上版本无实际作用。 - 修改
onActivityResult逻辑,直接使用返回的Uri完成视频预览:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == videoRequest && resultCode == Activity.RESULT_OK && data?.data != null) { feedImageSelect.visibility = View.GONE feedVideoSelect.visibility = View.VISIBLE pickedVideoUri = data.data!! // VideoView原生支持直接加载Uri,无需转字符串路径 feedVideoSelect.setVideoURI(pickedVideoUri) feedVideoSelect.setMediaController(MediaController(this)) feedVideoSelect.start() } }
- 上传Firebase Storage时,直接通过Uri获取输入流上传即可,不需要依赖本地文件路径:
val storageRef = FirebaseStorage.getInstance().reference // 自定义云端存储路径,这里用时间戳命名避免重名 val videoSaveRef = storageRef.child("upload_videos/${System.currentTimeMillis()}.mp4") val uploadTask = videoSaveRef.putStream(contentResolver.openInputStream(pickedVideoUri)!!) uploadTask.addOnSuccessListener { taskSnapshot -> // 上传成功,可通过taskSnapshot.downloadUrl拿到视频访问地址 }.addOnFailureListener { e -> // 处理上传失败逻辑 }
注意事项
- 如果项目targetSdkVersion ≥ 33(适配Android 13+),需要在
AndroidManifest.xml中声明android.permission.READ_MEDIA_VIDEO权限,不要使用已失效的READ_EXTERNAL_STORAGE权限,否则会出现无权限读取视频的问题。 startActivityForResult已经被官方废弃,后续建议替换为Activity Result API实现媒体选择,兼容性更好。
内容的提问来源于stack exchange,提问作者Prasad v Bhagat
相关产品推荐
相关产品推荐

