Android之Bitmap
2016-10-28 16:59
393 查看
加载Bitmap
BitmapFactory类提供了四类方法用来加载Bitmap:1、
decodeFile(...)通过图片路径加载,同时可以选择是否设置options,不设置则采用默认options。
例子:
Bitmap bm = BitmapFactory.decodeFile(sd_path)采用默认options
Bitmap bm = BitmapFactory.decodeFile(sd_path,options)
2、
decodeResource(...)通过传入Resource对象和
R.drawable.xxx形式加载。
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.aaa);默认options
3、
decodeStream(...)通过输入流加载
Bitmap bm = BitmapFactory.decodeStream(stream),这是一个耗时操作,要在子线程中执行
4、
decodeByteArray(...)从字节数组中加载。通过讲输入流inputstream转换成byte[]字节数组加载。
Bitmap bm = BitmapFactory.decodeByteArray(myByte,0,myByte.length);
** 注:**decodeFile和decodeResource间接调用decodeStream方法。
高效加载bitmap
如果图片过大,直接通过BitmapFactory加载,容易出现内存溢出。这样就需要采取一定策略来加载所需的图片。主要就是通过
BitmapFactory内部的一个内部类
Options来实现。
尺寸压缩 是压缩图片的像素,一张图片所占内存的大小 图片类型*宽*高,通过改变三个值减小图片所占的内存,防止OOM,当然这种方式可能会使图片失真 。这是必然的取舍。
设置Options,主要是设置图片色彩模式,采样率来实现。
Android图片色彩模式分类:
Bitmap.Config.ALPHA_8*:每个像素占用1byte内存。颜色信息只由透明度组成,占8位。
Bitmap.Config.ARGB_4444:每个像素占用2byte内存。颜色信息由透明度与R(Red),G(Green),B(Blue)四部分组成,每个部分都占4位,总共占16位。
Bitmap.Config.ARGB_8888:每个像素占用4byte内存。颜色信息由透明度与R(Red),G(Green),B(Blue)四部分组成,每个部分都占8位,总共占32位。是Bitmap默认的颜色配置信息,也是最占空间的一种配置。
Bitmap.Config.RGB_565:每个像素占用2byte内存。颜色信息由R(Red),G(Green),B(Blue)三部分组成,R占5位,G占6位,B占5位,总共占16位。
Android默认的色彩模式为ARGB_8888,这个色彩模式色彩最细腻,显示质量最高。但同样的,占用的内存也最大。
BitmapFactory.Options的
inPreferredConfig参数可以 指定decode到内存中,手机中所采用的编码,可选值定义在
Bitmap.Config中。缺省值是ARGB_8888。
采样率:
inSampleSize的值必须大于1时才会有效果,且采样率同时作用于宽和高;当inSampleSize=1时,采样后的图片为图片的原始大小。当inSampleSize=2时,采样后的图片的宽高均为原始图片宽高的1/2,这时像素为原始图片的1/(2x2),占用内存也为原始图片的1/(2x2);inSampleSize的取值应该总为2的整数倍,否则会向下取整,取一个最接近2的整数倍,比如inSampleSize=3时,系统会取inSampleSize=2。
假设一张1024x1024,模式为ARGB_8888的图片,inSampleSize=2,原始占用内存大小是4MB,采样后的图片占用内存大小就是(1024/2) x (1024/2 )x4 = 1MB。
public void decodeResource(View view) { Bitmap bm = decodeBitmapFromResource(); imageview.setImageBitmap(bm); } private Bitmap decodeBitmapFromResource(){ BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.drawable.bbbb, options); options.inSampleSize = calculateSampleSize(options,300,300); options.inJustDecodeBounds =false; return BitmapFactory.decodeResource(getResources(),R.drawable.bbbb,options); } // 计算合适的采样率(当然这里还可以自己定义计算规则),reqWidth为期望的图片大小,单位是px private int calculateSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){ Log.i("========","calculateSampleSize reqWidth:"+reqWidth+",reqHeight:"+reqHeight); int width = options.outWidth; int height =options.outHeight; Log.i("========","calculateSampleSize width:"+width+",height:"+height); int inSampleSize = 1; int halfWidth = width/2; int halfHeight = height/2; while((halfWidth/inSampleSize)>=reqWidth&& (halfHeight/inSampleSize)>=reqHeight){ inSampleSize*=2; Log.i("========","calculateSampleSize inSampleSize:"+inSampleSize); } return inSampleSize; }
优点: 效率较高,解析速度快
缺点:采样率inSampleSize的取值只能是2的次方数(例如:inSampleSize=15,实际取值为8;inSampleSize=17,实际取值为16;实际取值会往2的次方结算),因此该方法不能精确的指定图片的大小
Bitmap 注意事项
1、不用的bitmap即使释放if (!bmp.isRecycled()) { bmp.recycle(); //回收图片所占的内存 bitmap = null; system.gc(); //提醒系统及时回收 }
2、捕获OutOfMemoryError
bitmap在实例化的过程中是很耗内存的。很容易出现OutOfMemery内存溢出的情况。而且一出现程序就会crash。所以,需要对bitmap的实例化的时做OutOfMemoryError捕获,需要注意的是OutOfMemoryError并不是异常而是错误。一般情况下java中异常是可以捕获的。而错误是不可以的,因为Error的出现一般情况下程序就会终止。OutOfMemoryError比较特殊。
Bitmap bitmap = null; try { // 实例化Bitmap bitmap = BitmapFactory.decodeFile(path); } catch (OutOfMemoryError e) { > // 如果实例化失败 返回默认的Bitmap对象 return defaultBitmapMap; }
3、缓存通用的bitmap对象
在加载用户头像的时候,如果用户没有上传的头像,一般会加载一个默认头像。而用户的默认头像又是一样的,所以,对于相同头像的bitmap应该做缓存处理。
如果不进行缓存,尽管看到的是同一张图片文件,但是使用BitmapFactory类的方法来实例化出来的Bitmap,是不同的Bitmap对象。缓存可以避免新建多个Bitmap对象,避免内存的浪费。
4、图片质量压缩
上述用inSampleSize压缩是尺寸压缩,Android中还有一种压缩方式叫质量压缩。质量压缩是在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的,经过它压缩的图片文件大小(kb)会有改变,但是导入成bitmap后占得内存是不变的,宽高也不会改变。因为要保持像素不变,所以它就无法无限压缩,到达一个值之后就不会继续变小了。显然这个方法并不适用与缩略图,其实也不适用于想通过压缩图片减少内存的适用,
仅仅适用于想在保证图片质量的同时减少文件大小的情况而已。
private void compressImage(Bitmap image, int reqSize) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 质量压缩方法,这里100表示不压缩, image.compress(Bitmap.CompressFormat.JPEG, 100, baos); int options = 100; > // 循环判断压缩后的图片是否大于reqSize,大于则继续压缩 while (baos.toByteArray().length / 1024 > reqSize) { baos.reset();//清空baos // 这里压缩options,把压缩后的数据放到baos中 image.compress(Bitmap.CompressFormat.JPEG, options, baos); options -= 10; } // 把压缩后的baos放到ByteArrayInputStream中 ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray()); //decode图片 Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null); }
Android加载大量图片内存溢出解决方案
①、在加载图片的时候,尽量不要直接使用setImageBitmap或
setImageResource或
BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存,可以通过
BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source
③、运用Java软引用,进行图片缓存,将需要经常加载的图片放进缓存里,避免反复加载
相关文章推荐
- Android画图学习总结(二)——Bitmap
- Android中画bitmap的简单示例
- Android中Bitmap.createBitmap重载方总结 和 Android实现位图剪切
- understanding drawBitmapMesh on android
- android 位图bitmap
- Android Bitmap和Canvas
- Android Bitmap与Canvas
- Android当中的防锯齿(Bitmap & Canvas )
- android 保存bitmap到SD卡
- Android Bitmap和Canvas学习笔记
- android 中的 Bitmap 相关
- android中drawable转bitmap的两种方法
- Android UI开发专题(五) Bitmap和Canvas实例
- android --- Drawable、Bitmap、byte[]之间的转换
- Android Bitmap和Canvas学习笔记(转)
- Android Bitmap和Canvas
- Android UI开发专题(五) Bitmap和Canvas实例
- Android Bitmap和Canvas学习笔记
- 通过创建一个位图的XY Chart来学习Android绘图类Rect,Paint,Bitmap,Canvas(附源码)
- android----Bitmap / Drawable / byte[] 之间相互转化