您的位置:首页 > 移动开发 > Android开发

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软引用,进行图片缓存,将需要经常加载的图片放进缓存里,避免反复加载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息