前段时间买了一本android进阶的书,可是一直忙于工作,近期闲暇就看看,今天看了Bitmap的加载和Cache这部分,因为觉得有一部分还是比较费劲,虽然读过去了还是一知半解,所以准备先记录一下相对好理解的开始部分,然后慢慢品味,慢慢记录。所以这一篇先记录一下Bitmap的加载这部分。
BitmapFactory类提供了四类方法:
decodeFile 从文件系统加载一个Bitmap对象
decodeResource 从资源加载一个Bitmap对象
decodeStream 从输入流加载一个Bitmap对象
decodeByteArray 从字节数组加载一个Bitmap对象
加载大图的策略:
通过BitmapFactory.Options就可以按一定的采样率来加载缩小后的图片,将缩小后的图片显示在控件上,这样就能降低内存从而在一定程度上避免OOM,提高Bitmap加载时的性能。
BitmapFactory.Options缩放图片主要是用到了inSampleSize参数(采样率),当采样率的值为1的时候,相当于没有放缩,即和原图一样大,所以要实现缩小图片采样率的值就必须大于一,而且最新的官方文档指出,采样率的取值应该总是2的指数,即2,4,6,8,...。比如采样率取值2,那么最后得到的缩小图像素数和内容占用都为原图的1/4,即是宽和高都缩小了两倍。
通过采样率加载图片的流程大概可以有以下四个步骤:
1.将BitmapFactory.Options的inJustDecodeBounds参数值设置为true,并加载图片
2.从BitmapFactory.Options中取出图片的原始宽和高的信息,对应BitmapFactory.Options的outWidth和outHeight参数。
3.根据采样率的规则并结合目标View的所需大小,计算出采样率的取值。
4.将BitmapFactory.options的inJustDecodeBounds参数值设置为false,然后重新加载获取到缩小后的图片。
正常情况:
BitmapFactory获取图片的宽高也会按照drawable文件夹下的宽高设置来获取,所以获取到的结果也会不同,这一点我觉得几乎可以不做特别说明。
具体实现的代码如下:
/** * * @param res Resources * @param resId 资源Id * @param requestWidth 控件需要的实际宽度 * @param requestHeight 控件需要的实际高度 * @return */ public static Bitmap decodeSampledBitmapFromResource(Resources res,int resId,int requestWidth,int requestHeight){ //1.将BitmapFactory.Options的inJustDecodeBounds参数值设置为true,并加载图片 final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); //3.根据采样率的规则并结合目标View的所需大小,计算出采样率的取值。 options.inSampleSize = calculateInSampleSize(options,requestWidth,requestHeight); //4.将BitmapFactory.options的inJustDecodeBounds参数值设置为false,然后重新加载获取到缩小后的图片。 options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res,resId,options); } /** * * @param options BitmapFactory.Options * @param requestWidth 控件需要的实际宽度 * @param requestHeight 控件需要的实际高度 * @return */ private static int calculateInSampleSize(BitmapFactory.Options options, int requestWidth, int requestHeight) { //获取原始图片的宽和高 final int width = options.outWidth; final int height = options.outHeight; //初始化采样率 int inSampleSize = 1; if(width > requestWidth || height > requestHeight){ final int halfWidth = height/2; final int halfHeight = width/2; //计算最适合的采样率 while((halfWidth / inSampleSize) >= requestWidth && (halfHeight / inSampleSize) >= requestHeight){ inSampleSize *= 2; } } return inSampleSize; }使用:
iv.setImageBitmap(decodeSampledBitmapFromResource(getResources(),R.id.imageView,100,100));
这种策略对于除了decodeStream方法外有点儿特殊,其他三种都适用,关于decodeStream的特殊在Cache的时候应该会提到,这一篇先记录这一点儿