共计 1997 个字符,预计需要花费 5 分钟才能阅读完成。
Android 图片加载优化
在 Android 开发中图片加载往往是导致 OOM(Out of Memory)的主要原因,所以图片的压缩不得不作为 Android 开发中比用的一项技能点,以下将以简单的方式进行优化。
图片的大小如何被定义?
其实图片大小的计算是很简单的,只需要用图片的 width 乘以图片的 height 然后再乘以每一个像素所占用的字节数,这个字节数需要根据图片解码模式来获得,Android 中提供了 6 种方案,不过常用的只有三个,在下方已经列出。
A:透明度(Alpha)
R:红色(Red)
G:绿(Green)
B:蓝(Blue)
Bitmap.Config.ARGB_8888
:由 4 个 8 位组成,即 A =8,R=8,G=8,B=8,那么一个像素点占 8 +8+8+8=32 位(4 字节)
Bitmap.Config.ARGB_4444
:由 4 个 4 位组成,即 A =4,R=4,G=4,B=4,那么一个像素点占 4 +4+4+4=16 位(2 字节)
Bitmap.Config.RGB_565
:没有透明度,R=5,G=6,B=5,,那么一个像素点占 5 +6+5=16 位(2 字节)
基础知识补脑:
8bit(位)=1byte(字节)
1024byte=1KB
1024kb=1MB
1024mb=1GB
举例:
1、480×800 的图片,在色彩模式为 ARGB_8888 的情况下
480*800*4/1024/1024=1.46484375MB
2、480×800 的图片,在色彩模式为 ARGB_4444 的情况下
480*800*2/1024/1024=0.732421875MB
通过以上的测试,发现导致过大的原因主要集中在两点上,一点是图片的宽和高零一点则是解码方式,通过等比例缩放图片以及切换解码方式可以有效的降低图片的内存占用。不过在以下的优化方案中还有一种优化就是内存复用技术。
优化方案
缩放图片 + 质量压缩
var bitmapOptions = BitmapFactory.Options()
bitmapOptions.inJustDecodeBounds = true// 设置仅加载图片的宽高信息不将图片加载的内存中
BitmapFactory.decodeResource(resources, R.drawable.testimg, bitmapOptions)// 获取图片的宽高
bitmapOptions.inSampleSize = 4// 设置缩放比例(1、缩放图片)bitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565// 设置解码模式(2、质量压缩)bitmapOptions.inJustDecodeBounds = false// 消除仅加载图片的宽高
var bitmap = BitmapFactory.decodeResource(resources, R.drawable.testimg, bitmapOptions)// 加载图片到内存(注意添加 Option 对象)this.imgMain.setImageBitmap(bitmap)// 使用 Bitmap
inSampleSize 的作用就是可以把图片的宽高缩小 inSampleSize 倍,如下代码设置为 4 那么就是宽高的四分之一,所占内存缩小 inSampleSize 的平方。单纯的缩放 4 倍并不充分,只能说治标不治本,好比一个高清 50MB 的图片,你缩放 4 倍还是凉凉,所以说还是根据尺寸来计算需要缩放的倍数。
bitmapOptions.inSampleSize =Math.ceil(bitmapOptions.outWidth.toDouble() / targetWidth.toDouble()).toInt()// 设置缩放比例(1、缩放图片)
PS:以上的缩放并非精确的缩放
内存复用
何为内存复用,通俗来说就是我已经创建了一个 Bitmap 对象了,那么我接着还想用一个 bitmap 对象,那么就可以复用上一个 Bitmap 对象,不过这样做有两个缺点,第一就是会将之前的图片覆盖掉,第二就是后边加载的图片必须小于或者等于之前的图片大小,否则就不行。
var bitmapOptions1 = BitmapFactory.Options()
bitmapOptions1.inBitmap = bitmap// 绑定一个已经加载的 Bitmap 对象
var bitmap1 = BitmapFactory.decodeResource(resources, R.drawable.timg, bitmapOptions1)// 加载新的 Bitmap 对象
this.imgMain1.setImageBitmap(bitmap1)// 使用 Bitmap
其他方案
推荐使用 WEBP 格式代替 PNG 和 JPEG 图片格式。
写在最后
以上所说的只是简单的图片压缩优化,并非特定专业的优化方式,不过应对一般的项目需求应该还是可以满足的。