Android中Photo Picker选图后ExifInterface解析位置失败求助
问题:使用Photo Picker选图后无法通过ExifInterface获取图片位置信息
问题描述
开发地图图库应用时,原本通过ACTION_OPEN_DOCUMENT选择图片,借助MediaStore.Images.Media.EXTERNAL_CONTENT_URI生成InputStream传入ExifInterface,可以正常获取位置信息。但改用Photo Picker选图后,imageExif?.latLong始终为null,Logcat提示警告:'Latitude/longitude values are not parsable. latValue=0/1,0/1,0/1, latRef=, lngValue=0/1,0/1,0/1, lngRef='。
原实现代码
val fileInputStream = pickedImageUri?.let { it1 -> getInputStreamFromUri(context, it1) } Timber.e("pickedImageUri:$pickedImageUri") Timber.e("fileInputStream:$fileInputStream") val imageExif = fileInputStream?.let { it1 -> ExifInterface(it1) } Timber.e("imageExif:$imageExif") val imageLocationRaw = LatLng( imageExif?.latLong?.get(0) ?: 0.0, imageExif?.latLong?.get(1) ?: 0.0 ) if (imageExif != null) { Timber.e("latlong:${imageExif.latLong}") } Timber.e("imageLocationRaw:$imageLocationRaw")
原因分析
- Photo Picker默认返回缩略图流:Photo Picker为了性能优化,默认返回的是图片的缩略图输入流而非原图。缩略图通常会丢失完整的Exif元数据(包括位置信息),导致
ExifInterface解析到无效的位置参数。 - 资源访问权限限制:Photo Picker返回的Uri可能仅提供了缩略图的访问权限,或者读取流时未正确请求原图资源,导致无法获取包含位置信息的完整Exif数据。
解决方法
1. 强制请求原图资源
使用Photo Picker时,明确指定请求原图而非缩略图,构建Intent时配置正确参数:
// Android 13+ Photo Picker 配置 val pickerIntent = Intent(MediaStore.ACTION_PICK_IMAGES) pickerIntent.type = "image/*" pickerIntent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 1) startActivityForResult(pickerIntent, REQUEST_CODE_PICK_IMAGE)
获取Uri后,直接通过ContentResolver.openInputStream()读取原图资源,避免读取缩略图。
2. 通过MediaStore直接查询位置字段
绕过Exif解析,直接通过ContentResolver查询图片的纬度和经度元数据,这种方式更可靠:
fun getImageLocation(context: Context, uri: Uri): LatLng? { var latLng: LatLng? = null context.contentResolver.query( uri, arrayOf(MediaStore.Images.Media.LATITUDE, MediaStore.Images.Media.LONGITUDE), null, null, null )?.use { cursor -> if (cursor.moveToFirst()) { val lat = cursor.getDouble(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.LATITUDE)) val lng = cursor.getDouble(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.LONGITUDE)) if (lat != 0.0 || lng != 0.0) { // 排除默认无效值 latLng = LatLng(lat, lng) } } } return latLng }
调用该方法即可直接获取图片位置,无需依赖ExifInterface解析流。
3. 申请持久化Uri权限
如果需要长期访问图片资源,在获取Photo Picker返回的Uri后,申请持久化权限避免后续访问受限:
val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION context.contentResolver.takePersistableUriPermission(uri, takeFlags)
内容的提问来源于stack exchange,提问作者Ruineie
相关产品推荐
相关产品推荐

