在上一篇文章 ViewModel + LiveData 初探 中的场景中,有获取手机媒体数据的操作,界面上也要展示横竖屏,展示规则很简单:宽度不小于高度则定义为横屏,否则未竖屏。在我的小米 MIX2 上,不论手机如何拍照,返回的分辨率都是 4000:3000(根据相机设置中的画幅比例),不论你是横着拍还是竖着拍。所以当拿到 4000:3000 后就全部定义成横屏了,与实际不符。所以着手解决了一下,顺便整理下获取手机媒体数据的相关代码,方便日后使用。整体代码如下:
1 | object MediaDataUtils { |
利用我的小米 MIX2 使用 18:9 画幅比例竖屏拍摄的一张照片,在我的 Rom 里显示的是 4000:2000,将这张照片放到同事的华为手机里,显示的分辨率则是另外一个数,但是华为 Rom 里获取的高宽比例是一致的,宽:高 = 1 : 2,所以在我的手机里识别成横屏照片,在华为手机里识别为竖屏照片。所以仅仅使用 MediaStore.MediaColumns.WIDTH、MediaStore.MediaColumns.HEIGHT 获取的宽高是不准确的,需要一个更好的方案:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32/**
* 读取图片的宽高信息,系统多媒体数据库保存的宽高信息是通过读取图片 ExifInterface 数据
* 某些手机拍照生成的 exif 数据不准,此处使用 BitmapDecode 的方式获取,经测试耗时可忽略不计
*/
private fun readImagePixel(filePath: String?): Pair<Int, Int>? {
if (!FileUtils.exists(filePath)) {
return null
}
try {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(filePath, options)
val width = options.outWidth
val height = options.outHeight
if (width > 0 && height > 0) {
val exifInterface = ExifInterface(filePath)
val orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL)
// 如果图片的旋转角度为 90 或者 270,则宽高互换
if (orientation == ExifInterface.ORIENTATION_ROTATE_90
|| orientation == ExifInterface.ORIENTATION_ROTATE_270) {
return Pair(height, width)
}
return Pair(width, height)
}
} catch (e: Exception) {
LogUtils.e(TAG, e.message)
}
return null
}
当照片数量很多(我的手机 2200+ 张照片)时,遍历完耗时大概在 3 ~ 4 秒,在接受范围内吧。
另外对于小米 MIX2 拍摄的视频数据,获取的宽高会是 0,所以也需要一种方案获取比例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34/**
* 读取视频的宽高数据
* 需要根据拍摄方向进行转换,有点耗时平均五六十毫秒
*/
private fun readVideoPixel(filePath: String?): Pair<Int, Int>? {
if (!FileUtils.exists(filePath)) {
return null
}
val mmr = MediaMetadataRetriever()
try {
mmr.setDataSource(filePath)
val width = mmr.extractMetadata(android.media.MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt()
?: 0
val height = mmr.extractMetadata(android.media.MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt()
?: 0
val orientation = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION).toInt()
if (width > 0 && height > 0) {
if (orientation == 90 || orientation == 270) {
return Pair(height, width)
}
return Pair(width, height)
}
} catch (e: Exception) {
LogUtils.e(TAG, e.message)
} finally {
try {
mmr.release()
} catch (e: Throwable) {
LogUtils.e(TAG, e.message)
}
}
return null
}
视频数量一般比较少,耗时问题暂时可以不考虑。使用此种方案后,照片、视频的横竖问题基本准确。Over~
题外话
当手机视频、照片数量特别多了之后,一次加载全部就耗时有些久了,手机里 50 多个视频耗时 2 秒多,2000 多张照片耗时 5 秒左右,所以需要调整成为分页加载。利用 limit + offset 来实现:1
val order = ORDER_BY + " limit " + PAGE_SIZE + " offset " + (page - 1) * PAGE_SIZE
有了分页就可能出现重复数据了(第一页加载完后,又拍了 2 张照片,下一页加载的数据会有 2 条重复),所以要注意去重。