Bitmap即位图。在Android中要处理要位图的加载显示并不容易,需要娴熟的管理的设备内存,否则很容易因为位图的加载不恰当占用了应用大量宝贵的内存空间,更严重的导致应用OOM。因此学习好如何高效的加载内存十分重要。幸好,现在有许多十分强大的图片加载框架,它们能够高效顺畅的加载位图,使用起来也非常方便,譬如Glide,picasso等。本文也暂时不去分析这些框架的源码(没复习到,也真的很复杂,不是三言两语能说明白的)。
Bitmap的加载优化呢,大概有三种:
1.采用图片质量较低(低色彩)的位图。譬如RGB_565每个像素占2个字节,ARGB_8888每个像素占4个字节。
2.将不同像素图片放到对应的drawable目录下。
这两个答案有个博主的文章说的十分详细(真大佬)https://www.jianshu.com/p/3f6f6e4f1c88。
3.加载图片经过缩略后的位图。
第3种方法能够节约位图占用的内存是很明显的。前面两步在日常的开发中都应该能够不犯错误,即使前两种方法都做到了内存优化,但是图片的像素仍然比较大,譬如4048*3036像素,图片质量为RGB_565,位图加载内存中仍然需要4048*3036*2 大约24M的内存,即使是现在的手机有6G运行内存,一张图片要占据24M的内存还是不能让人满意的。因此,我们要做到更加高效的加载位图。
通常我们解码位图的时候都会调用BitmapFactory的一系列decodeXXX()方法,这些decodeXXX()方法最后后会调用底层Native方法去解码位图。
底层解码位图会试图为位图分配内存空间,所以在我们调用解码方法的时候,要先设置BitmapFactory.Option类的属性inJustDecodeBounds为true, 可避免内存分配。
这段代码可以在不分配内存就可以获取位图的尺寸(宽,高,类型)。在得知了位图的宽高之后我们就可以对位图进行缩略在加载到控件上。
为什么inSampleSize要为2的n次幂呢?是因为解码器使用的最终值将向下舍入为最接近的 2 的幂,也就是说我们最终在Native方法去解码的时候,使用这个缩略大小inSampleSize是向下舍入为最接近的 2 的幂。具体可以看看这个inSampleSize文档说明。
最终我们可以得出高效加载位图的方法。
mIVBeauty.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.iv_beauty, 100, 100));
private Bitmap decodeSampledBitmapFromResource(Resources resources, int resID, int reqWidth, int reqHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(resources, resID, options);
int inSampleSize = calcInSampleSize(options, reqWidth, reqHeight);
options.inSampleSize = inSampleSize;
return BitmapFactory.decodeResource(resources, resID, options);
}