如何通过ActivityResultContracts.PickVisualMedia获取图片真实Uri
如何将PhotoPicker返回的Uri转换为真实媒体Uri并存入Room
使用ActivityResultContracts.PickVisualMedia()返回的是PhotoPicker的代理Uri(格式如content://media/picker/...),而非直接指向媒体库的真实Uri。要获取你需要的content://media/external/images/media/xxx格式Uri,需通过ContentResolver查询该代理Uri对应的媒体ID,再拼接出真实Uri,具体步骤如下:
1. 实现Uri转换函数
通过ContentResolver查询代理Uri对应的媒体ID,再构建真实媒体Uri:
fun getRealImageUri(context: Context, pickerUri: Uri): Uri? { // 只查询媒体ID字段,减少性能开销 val projection = arrayOf(MediaStore.Images.Media._ID) context.contentResolver.query( pickerUri, projection, null, null, null )?.use { cursor -> // 游标移动到第一条数据(因为是单图选择) if (cursor.moveToFirst()) { val mediaId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)) // 拼接真实的图片媒体Uri return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mediaId.toString()) } } return null }
如果是选择视频,只需将MediaStore.Images替换为MediaStore.Videos即可。
2. 在Picker回调中获取并存储真实Uri
在Launcher的onResult回调里调用转换函数,得到真实Uri后存入Room:
// 在Compose中获取Context val context = LocalContext.current val singlePhotoPickerLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.PickVisualMedia(), onResult = { pickerUri -> pickerUri?.let { val realImageUri = getRealImageUri(context, it) realImageUri?.let { uri -> selectedImageUri = uri // 将Uri转为字符串存入Room(避免直接存储Uri的序列化问题) yourRoomRepository.saveImageUri(uri.toString()) } } } )
注意事项
- 权限要求:Android 13及以上需要申请
READ_MEDIA_IMAGES权限;Android 12及以下需要READ_EXTERNAL_STORAGE权限,否则查询会返回null。 - Room存储:直接存储Uri对象可能存在序列化问题,建议将Uri转为字符串存入,取出时通过
Uri.parse(uriString)还原。
内容的提问来源于stack exchange,提问作者1234567
相关产品推荐
相关产品推荐

