Bitmap

来源:互联网 发布:林珊珊的淘宝店 编辑:程序博客网 时间:2024/04/30 10:46

参考:http://www.jianshu.com/p/98c88f9ceafa

一、Bitmap的基本加载

BitmapFactory类提供了四类方法用来加载Bitmap:
(1)decodeFile从文件系统加载
a、通过Intent打开本地图片或者照片
b、在onActivityResult中获取图片uri
c、根据uri获取图片路径
d、根据路径解析bitmap
Bitmap bm=BitmapFactory.decodeFile(sd_path);
(2)decodeResource以R.drawable.xxx的形式从本地资源中加载

Bitmap bm=BimmapFactory.decodeResource(getResource(),R.drawable.aaa);

(3)decodeStream从输入流中加载
a、开启异步线程去获取网络图片
b、网络返回InputStream
c、解析Bitmap bm=BitmapFactory.decodeStream(stream)这是一个耗时操作,要在子线程中执行
(4)decodeByteArray从字节数组中加载
a、开启异步线程去获取网络图片
b、网络返回InputStream
c、把InputStream转换成byte[]
d、解析Bitmap bm=BitmapFactory.decodeByteArray(myByte,0,myByte.length);

二、高效的加载Bitmap

在使用bitmap时,经常会出现内存溢出等情况,所以需要高效的使用bitmap

思路:使用系统提供给我们的Options类来处理,前面四个基本加载图片的方法都支持options。通过BitmapFactory.Options按一定的采样率来加载缩小后的图片,然后在ImageView中使用缩小的图片这样就会降低内存占用避免OOM,提高了Bitmap的加载性能,当然这种方式可能会使图片失真

预备知识
1、Android色彩模式说明

  • ALPHA_8:每个像素占用1byte内存
  • ARGB_4444:每个像素占用2byte内存
  • ARGB_8888:每个像素占用4byte内存
  • RGB_565:每个像素占用2byte内存

Android默认的色彩模式是ARGB_8888,这个色彩模式色彩最细腻,显示质量最高,但是占用的内存最大:BitmapFactory.Options的inPreferredConfig参数可以指定decode到内存中、手机中所采用的编码,可选值定义在Bitmap.Config中,缺省值是ARGB_8888

假设一张1-24*1024的图片,模式为ARGB_8888,那么它占用的内存就是1024*1024*4=4MB

2、采样率inSampleSize

  • 采样率同时作用于图片的宽和高,当inSampleSize=1时,采样后的图片为图片的原始大小,当inSampleSize=2时,采样后的图片是原始图片的1/(2*2)
  • inSampleSize的取值应该总是为2的整数倍,否则会向下取整,比如inSampleSize=3,系统会取inSampleSize=2

高效加载的步骤
1、将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片(当inJustDecodeBounds为true时,执行decodexxx方法时,BitmapFactory只会解析图片的原始高宽信息,并不会真正的加载图片)
2、从BitmapFactory.Options取出图片的原始宽高(outWidth,outHeight)信息
3、选取合适的采样率inSampleSize
4、将BitmapFactory.Options的inJustDecodeBounds参数设为false并重新加载图片
代码如下:

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(getResource,R.drawable.bbb,options);    options.inSampleSize=calculateSampleSize(options,300,300);    options.inJustDecodeounds=false;    return BitmapFactory.decodeResource(getResources(),R.drawable.bbb,iptions);    }//计算合适的采样率(可以自己定义规则),reqWidth为期望的图片大小,单位是pxprivate int calculateSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){    int width=options.outWidth;    int height=options.outHeight;    int inSampleSize=1;    int halfWidth=width/2;    int halfHeight=height/2;    while((halfWidth/inSampleSize)>reqWidth&&(halfHeigth/inSampleSize)>=reqHeight){    inSampleSize*=2;    }    return inSampleSize;    }

三、使用Bitmap时的注意事项

1、不用的Bitmap及时释放

if (!bmp.isRecycle()) {    bmp.recycle();   //回收图片所占的内存    bitmap = null;    system.gc();  //提醒系统及时回收}

虽然调用recycle()并不能保证立即释放占用的内存,但可以加速Bitmap内存的释放。释放内存之后就不能再使用该Bitmap对象了

2、捕获异常
因为Bitmap非常耗内存,为了避免应用在分配Bitmap内存的时候出现OutOfMemory异常以后Crash掉,在实例化Bitmap的代码中,一定要对OutOfMemory异常进行捕获,但是直接捕获Excetion是捕获不到的,因为OutOfMemoryError是一种Error,不是Exception

Bitmap bitmap=null;try{    //实例化Bitmap    bitmap=BitmapFactory.decodeFile(path);    }catch(OutOfMemoryError e){    }    if(bitmap==null){    return defaultBitmapMap;//如果实例化失败,返回默认的Bitmap对象    }

3、缓存通用的Bitmap对象
有时候,可能需要在一个Activity里多次用到同一张图片。比如一个Activity会展示一些用户的头像列表,而如果用户没有设置头像的话,则会显示一个默认头像,而这个头像是位于应用程序本身的资源文件中的。如果有类似上面的场景,就可以对同一Bitmap进行缓存。如果不进行缓存,尽管看到的是同一张图片文件,但是使用BitmapFactory类的方法来实例化出来的Bitmap,是不同的Bitmap对象。缓存可以避免新建多个Bitmap对象,避免内存的浪费。在Android应用开发过程中所说的缓存有两个级别,一个是硬盘缓存,一个是内存缓存。

4、图片的质量压缩

上述用inSampleSize压缩是尺寸压缩,Android中还有一种压缩方式叫质量压缩。质量压缩是在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的,经过它压缩的图片文件大小会有改变,但是导入成bitmap后占得内存是不变的,宽高也不会改变。因为要保持像素不变,所以它就无法无线压缩,到达一个值之后就不会继续压缩变小了。显然这个方法并不适用于缩略图,其实也不适用于想通过压缩图片减小内存的情况,仅仅适用于想在保证图片质量的同时减小文件大小的情况

  private void compressImage(Bitmap image, int reqSize) {        ByteArrayOutputStream baos = new ByteArrayOutputStream();        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,        int options = 100;        while (baos.toByteArray().length / 1024 > reqSize) { // 循环判断压缩后的图片是否大于reqSize,大于则继续压缩            baos.reset();//清空baos            image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据放到baos中            options -= 10;        }        // 把压缩后的baos放到ByteArrayInputStream中        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());        //decode图片        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);    }

5、Android加载大量图片内存溢出解决方案
(1)尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存,可以通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source
(2)使用BitmapFactory.Options对图片进行压缩(上述第二部分)
(3)运用Java软引用,进行图片缓存,将需要经常加载的图片放进缓存里,避免反复加载

0 0
原创粉丝点击