Android开发 —— Bitmap的高效加载

0. 前言

图片加载是Android开发的重要环节之一。现在,第三方图片加载框架很流行,如bumptech的Glide、Square的Picasso、Facebook的Fresco以及Google的网络请求框架Volley。

其中,Glide是Google官方推荐的图片加载框架。当然,这些主流的框架都包含了图片的高效加载策略和缓存策略。


0.1 为什么需要Bitmap的高效加载

Bitmap在Android中指的是一张图片,可以是png格式也可以是jpg等其他常见格式。


现在的图片都比较大,而Android对单个应用的内存占用有所限制,这就会导致在加载Bitmap的时候容易出现内存溢出OOM。

为了解决这个问题,就出现了Bitmap的高效加载策略。


它的核心思想很简单,就是采用BitmapFactory.Options来加载所需尺寸的图片。

假设通过ImageView来显示图片,很多时候ImageView并没有原始图片的尺寸那么大,这个时候把整个图片加载进来后再设置给ImageView,

显然是没有必要的,因为ImageView根本没办法显示原始图片。这时候就可以按一定的采样率来将图片缩小后再加载进来,

这样图片既能在ImageView显示出来,又能降低内存占用从而在一定程度上避免OOM,提高了Bitmap加载时的性能。


1. 加载Bitmap

BitmapFactory类提供了4个方法:

decodeFile()、decodeResource()、decodeStream()和decodeByteArray()

分别用于从文件系统、资源、输入流以及字节数组中加载出一个Bitmap对象。


2. 高效加载Bitmap

通过BitmapFactory.Options可以按一定的采样率来加载缩小后的图片。

BitmapFactory提供的加载图片的4类方法都支持BitmapFactory.Options参数。


2.1 inSampleSize参数

即采样率

当inSampleSize小于等于1时,无缩放效果,即采样后的图片大小为图片的原始大小;

当inSampleSize大于1时,采样后的图片大小为原图片大小的1 / (inSampleSize的平方)。

inSampleSize的取值应为2的指数,如1、2、4、8、16等。


例子:一张1024*1024像素的图片,假定采用ARGB8888存储,那么它占内存为1024*1024*4=4MB。

如果inSampleSize=2,那么采样后的图片占内存为512*512*4=1MB。


inSampleSize参数的取值应根据ImageView的大小和图片的原始大小来选择。


2.2 inJustDecodeBounds参数

当inJustDecodeBounds为true时,BitmapFactory只会解析图片的原始宽高信息,并不会真正地加载图片,所以这个操作是轻量级的。

注:此时,BitmapFactory获取的图片宽高信息和图片位置与程序运行的设备有关。

比如同一张图片放在不同的drawable目录下或者程序运行在不同屏幕密度的设备上,都可能导致BitmapFactory获取不同的结果。

之所以会出现这个现象,这和Android的资源加载机制有关。


3. 高效加载Bitmap的流程

(1) 将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片。

(2) 从BitmapFactory.Options中取出图片的原始宽高信息,它们对应于outWidth和outHeight参数。

(3) 根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize。

(4) 将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后重新加载图片。

经过上面的4个步骤,加载出来的图片就是最终缩放后的图片,当然也有可能不需要缩放。


4. 高效加载Bitmap的代码实现

public static Bitmap decodeSampledBitmapFromResource(Resource res, int resId,
	int reqWidth, int reqHeight) {
	// 将inJustDecodeBounds参数设为true并加载图片
	final BitmapFactory.Options options = new BitmapFactory.Options();
	options.inJustDecodeBounds = true;
	BitmapFactory.decodeResource(res, resId, options);

	// 计算采样率inSampleSize
	options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

	// 将inJustDecodeBounds参数设为false并重新加载图片
	options.inJustDecodeBounds = false;
	return BitmapFactory.decodeResource(res, resId, options);
}

public static int calculateInSampleSize(BitmapFactory.Options options,
	int reqWidth, int reqWidth) {
	// 取出图片的原始宽高信息
	final int width = options.outWidth;
	final int height = options.outHeight;
	int inSampleSize = 1;

	if (width > reqWidth || height > reqHeight) {
		final int halfWidth = width / 2;
		final int halfHeight = height / 2;
		// 根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize
		while ((halfWidth / inSampleSize) >= reqWidth
			&& (halfHeight / inSampleSize) >= reqHeight) {
			inSampleSize *= 2;
		}
	}

	return inSampleSize;
}
实际使用:比如ImageView所期望的图片大小为100*100像素,可以通过以下方式高效加载并显示图片

mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResource(), R.id.myimage, 100, 100));



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值