Android之Bitmap

来源:互联网 发布:江苏清华紫光软件集团 编辑:程序博客网 时间:2024/06/02 02:48

加载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.OptionsinPreferredConfig参数可以 指定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为期望的图片大小,单位是pxprivate 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加载大量图片内存溢出解决方案

①、在加载图片的时候,尽量不要直接使用setImageBitmapsetImageResourceBitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存,可以通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source

③、运用Java软引用,进行图片缓存,将需要经常加载的图片放进缓存里,避免反复加载

1 0
原创粉丝点击