在Android系统中,其实操作的是位图,即:Bitmap。我们知道在windows、macos等一些系统上支持jpg、png、webp等图片格式。为了提高文件的传输以及显示速度可以把图片经过算法把文件压缩成不同的格式,或者使文件变小就可以达到目的。但是在android系统上显示完全就不是这么回事了。
在Android显示一张图片,不管图片是JPEG、PNG、WEBP格式的都需要把这些图片解码成位图格式后Android系统才能正常的显示出来。
我们都知道图片在app中是非常的占用内存的,具体为什么如此占用内存下面就来说到说到,完事后基本上就对如何优化图片内存有一个大概的方向了。
在Android中一张图片被解码成位图以后其占用运行时内存的大小只和图片的质量和大小有关系。即:图片的长度、图片的宽度、单位像素所占的字节数。
公式如下:Bitmap所占内存=图片的宽度 * 图片的高度 * 单位像素所占的字节数(图片的长度和宽度的单位是像素)
根据以上的公式我们在优化Bitmap的时候大概有两种思路,当然这两种思路也可以公用。其原理就是让三个变量相乘的乘积尽量的小就行了。
1.降低图片质量(即减少单位像素所占字节数的大小)
2.缩小图片的大小(宽高)
一、降低图片质量
Android系统在默认的情况下把图片解码成位图后,会被处理成32bit/像素。即红、绿、蓝、透明通道各8bit(即使有些图片没有透明通道依然会被处理掉)。所以我们要更改图片的质量可以把图片解码时的默认bit/像素数处理的小一点。这个时候就需要使用到位图规格了。下面看一张图片,如果有小伙伴用过imageloader或者glide或者其他一些处理图片的开源库的时候就会非常的熟悉。
以上就是Android系统支持的四种位图格式。ARGB_8888是android系统默认的其规格是32bit/像素。其ARGB_4444和RGB_565的规格是16bit/像素。所以要优化图片的规格只需要把系统默认的规格改成这两个规格就行了。这样做虽然图片的内存占用减少了,但是其付出的代价是视觉体验受损的。因为ARGB_4444和RGB_565减少了图片的像素数。但是如果能够根据使用场景灵活的时候这三种规格,其实还是非常不错的。例如:头像、小图可以使用ARGB_4444和RGB_565,在查看清晰的大图的时候再使用ARGB_8888的规格。
如何更改位图的默认规格呢?下面给出示例代码
BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_4444;//把默认规格改成ARGB_444 Bitmap bitmap = BitmapFactory.decodeStream(in,null,options);
二、改变图片的大小
在某些场景下,手机屏幕上需要显示的图片的宽高为:50px*50px,而图片实际转换为位图后的大小为100px*100px。在这种场景下本来我们要开辟的内存为50*50*单位像素所占字节数就够了。而实际上我们缺开辟出来100*100*单位像素所占字节数。所以这种情况下就造成了显示内存的严重浪费。而且这种问题经常会出现,例如:显示头像、显示缩略图等场景。
所以我们在开发中尽量把屏幕要显示的图片大小和实际上内存中图片的大小一致就能很好的解决内存的浪费。在Options中为开发者提供了一个inSimpleSize属性,其会以2的幂函数来缩小图片。
例如:inSimpleSize=2其图片大小变为原来的二分之一,inSimpleSize=8,图片则变为原来的八分之一。示例代码如下:
BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_4444;//把默认规格改成ARGB_444 options.inSampleSize = 4;//图片未原图的四分之一 Bitmap bitmap = BitmapFactory.decodeStream(in,null,options);
总结:优化Bitmap所占内存最常见,效果最好的就是这两个策略(降低图片质量、减小图片大小)。当然除了这两种方式还有一些辅助策略,如:更精准的缩放图片(inScaled、inDensity、inTargetDensity)。再如使用inBitmap属性来重用Bitmap所占内存。
乖乖在家坐月子??