Bitmap详解与Bitmap的内存优化.docx
《Bitmap详解与Bitmap的内存优化.docx》由会员分享,可在线阅读,更多相关《Bitmap详解与Bitmap的内存优化.docx(19页珍藏版)》请在冰豆网上搜索。
Bitmap详解与Bitmap的内存优化
Bitmap详解与Bitmap的内存优化
一、Bitmap:
Bitmap是Android系统中的图像处理的最重要类之一。
用它可以获取图像文件信息,进行图像剪切、旋转、缩放等操作,并可以指定格式保存图像文件。
常用方法:
+publicvoidrecycle() //回收位图占用的内存空间,把位图标记为Dead
+publicfinalbooleanisRecycled() //判断位图内存是否已释放
+publicfinalintgetWidth() //获取位图的宽度
+publicfinalintgetHeight() //获取位图的高度
+publicfinalbooleanisMutable() //图片是否可修改
+publicintgetScaledWidth(Canvascanvas) //获取指定密度转换后的图像的宽度
+publicintgetScaledHeight(Canvascanvas) //获取指定密度转换后的图像的高度
+publicbooleancompress(CompressFormatformat,intquality,OutputStreamstream) //按指定的图片格式以及画质,将图片转换为输出流。
format:
压缩图像的格式,如Bitmap.CompressFormat.PNG或Bitmap.CompressFormat.JPEG
quality:
画质,0-100.0表示最低画质压缩,100以最高画质压缩。
对于PNG等无损格式的图片,会忽略此项设置。
stream:
OutputStream中写入压缩数据。
return:
是否成功压缩到指定的流。
+publicstaticBitmapcreateBitmap(Bitmapsrc) //以src为原图生成不可变得新图像
+publicstaticBitmapcreateScaledBitmap(Bitmapsrc,intdstWidth,intdstHeight,booleanfilter) //以src为原图,创建新的图像,指定新图像的高宽以及是否可变。
+publicstaticBitmapcreateBitmap(intwidth,intheight,Configconfig) //创建指定格式、大小的位图
+publicstaticBitmapcreateBitmap(Bitmapsource,intx,inty,intwidth,intheight) //以source为原图,创建新的图片,指定起始坐标以及新图像的高宽。
二、BitmapFactory工厂类:
Option参数类:
+publicbooleaninJustDecodeBounds //如果设置为true,不获取图片,不分配内存,但会返回图片的高度宽度信息。
如果将这个值置为true,那么在解码的时候将不会返回bitmap,只会返回这个bitmap的尺寸。
这个属性的目的是,如果你只想知道一个bitmap的尺寸,但又不想将其加载到内存时。
这是一个非常有用的属性。
+publicintinSampleSize //图片缩放的倍数
这个值是一个int,当它小于1的时候,将会被当做1处理,如果大于1,那么就会按照比例(1/inSampleSize)缩小bitmap的宽和高、降低分辨率,大于1时这个值将会被处置为2的倍数。
例如,width=100,height=100,inSampleSize=2,那么就会将bitmap处理为,width=50,height=50,宽高降为1/2,像素数降为1/4。
+publicintoutWidth //获取图片的宽度值
+publicintoutHeight //获取图片的高度值
表示这个Bitmap的宽和高,一般和inJustDecodeBounds一起使用来获得Bitmap的宽高,但是不加载到内存。
+publicintinDensity //用于位图的像素压缩比
+publicintinTargetDensity //用于目标位图的像素压缩比(要生成的位图)
+publicbyte[]inTempStorage //创建临时文件,将图片存储
+publicbooleaninScaled //设置为true时进行图片压缩,从inDensity到inTargetDensity
+publicbooleaninDither //如果为true,解码器尝试抖动解码
+publicBitmap.ConfiginPreferredConfig //设置解码器
这个值是设置色彩模式,默认值是ARGB_8888,在这个模式下,一个像素点占用4bytes空间,一般对透明度不做要求的话,一般采用RGB_565模式,这个模式下一个像素点占用2bytes。
+publicStringoutMimeType //设置解码图像
+publicbooleaninPurgeable //当存储Pixel的内存空间在系统内存不足时是否可以被回收
+publicbooleaninInputShareable //inPurgeable为true情况下才生效,是否可以共享一个InputStream
+publicbooleaninPreferQualityOverSpeed //为true则优先保证Bitmap质量其次是解码速度
+publicbooleaninMutable //配置Bitmap是否可以更改,比如:
在Bitmap上隔几个像素加一条线段
+publicintinScreenDensity //当前屏幕的像素密度
工厂方法:
+publicstaticBitmapdecodeFile(StringpathName,Optionsopts) //从文件读取图片
+publicstaticBitmapdecodeFile(StringpathName)
+publicstaticBitmapdecodeStream(InputStreamis) //从输入流读取图片
+publicstaticBitmapdecodeStream(InputStreamis,RectoutPadding,Optionsopts)
+publicstaticBitmapdecodeResource(Resourcesres,intid) //从资源文件读取图片
+publicstaticBitmapdecodeResource(Resourcesres,intid,Optionsopts)
+publicstaticBitmapdecodeByteArray(byte[]data,intoffset,intlength) //从数组读取图片
+publicstaticBitmapdecodeByteArray(byte[]data,intoffset,intlength,Optionsopts)
+publicstaticBitmapdecodeFileDescriptor(FileDescriptorfd) //从文件读取文件与decodeFile不同的是这个直接调用JNI函数进行读取效率比较高
+publicstaticBitmapdecodeFileDescriptor(FileDescriptorfd,RectoutPadding,Optionsopts)
*Bitmap.ConfiginPreferredConfig:
*
枚举变量(位图位数越高代表其可以存储的颜色信息越多,图像越逼真,占用内存越大)
+publicstaticfinalBitmap.ConfigALPHA_8 //代表8位Alpha位图每个像素占用1byte内存
+publicstaticfinalBitmap.ConfigARGB_4444 //代表16位ARGB位图每个像素占用2byte内存
+publicstaticfinalBitmap.ConfigARGB_8888 //代表32位ARGB位图每个像素占用4byte内存
+publicstaticfinalBitmap.ConfigRGB_565 //代表8位RGB位图每个像素占用2byte内存
Android中一张图片(BitMap)占用的内存主要和以下几个因数有关:
图片长度,图片宽度,单位像素占用的字节数。
一张图片(BitMap)占用的内存=图片长度*图片宽度*单位像素占用的字节数。
三、Bitmap加载方式
Bitmap的加载方式有Resource资源加载、本地(SDcard)加载、网络加载等加载方式。
1.从本地(SDcard)文件读取
方式一
/**
*获取缩放后的本地图片
*
*@paramfilePath文件路径
*@paramwidth宽
*@paramheight高
*@return
*/
publicstaticBitmapreadBitmapFromFile(StringfilePath,intwidth,intheight){
BitmapFactory.Optionsoptions=newBitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeFile(filePath,options);
floatsrcWidth=options.outWidth;
floatsrcHeight=options.outHeight;
intinSampleSize=1;
if(srcHeight>height||srcWidth>width){
if(srcWidth>srcHeight){
inSampleSize=Math.round(srcHeight/height);
}else{
inSampleSize=Math.round(srcWidth/width);
}
}
options.inJustDecodeBounds=false;
options.inSampleSize=inSampleSize;
returnBitmapFactory.decodeFile(filePath,options);
}
方式二(效率高于方式一)
/**
*获取缩放后的本地图片
*
*@paramfilePath文件路径
*@paramwidth宽
*@paramheight高
*@return
*/
publicstaticBitmapreadBitmapFromFileDescriptor(StringfilePath,intwidth,intheight){
try{
FileInputStreamfis=newFileInputStream(filePath);
BitmapFactory.Optionsoptions=newBitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeFileDescriptor(fis.getFD(),null,options);
floatsrcWidth=options.outWidth;
floatsrcHeight=options.outHeight;
intinSampleSize=1;
if(srcHeight>height||srcWidth>width){
if(srcWidth>srcHeight){
inSampleSize=Math.round(srcHeight/height);
}else{
inSampleSize=Math.round(srcWidth/width);
}
}
options.inJustDecodeBounds=false;
options.inSampleSize=inSampleSize;
returnBitmapFactory.decodeFileDescriptor(fis.getFD(),null,options);
}catch(Exceptionex){
}
returnnull;
}
2.从输入流中读取文件(网络加载)
/**
*获取缩放后的本地图片
*
*@paramins输入流
*@paramwidth宽
*@paramheight高
*@return
*/
publicstaticBitmapreadBitmapFromInputStream(InputStreamins,intwidth,intheight){
BitmapFactory.Optionsoptions=newBitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeStream(ins,null,options);
floatsrcWidth=options.outWidth;
floatsrcHeight=options.outHeight;
intinSampleSize=1;
if(srcHeight>height||srcWidth>width){
if(srcWidth>srcHeight){
inSampleSize=Math.round(srcHeight/height);
}else{
inSampleSize=Math.round(srcWidth/width);
}
}
options.inJustDecodeBounds=false;
options.inSampleSize=inSampleSize;
returnBitmapFactory.decodeStream(ins,null,options);
}
3.Resource资源加载
Res资源加载方式:
publicstaticBitmapreadBitmapFromResource(Resourcesresources,intresourcesId,intwidth,intheight){
BitmapFactory.Optionsoptions=newBitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeResource(resources,resourcesId,options);
floatsrcWidth=options.outWidth;
floatsrcHeight=options.outHeight;
intinSampleSize=1;
if(srcHeight>height||srcWidth>width){
if(srcWidth>srcHeight){
inSampleSize=Math.round(srcHeight/height);
}else{
inSampleSize=Math.round(srcWidth/width);
}
}
options.inJustDecodeBounds=false;
options.inSampleSize=inSampleSize;
returnBitmapFactory.decodeResource(resources,resourcesId,options);
}
此种方式相当的耗费内存建议采用decodeStream代替decodeResource可以如下形式:
publicstaticBitmapreadBitmapFromResource(Resourcesresources,intresourcesId,intwidth,intheight){
InputStreamins=resources.openRawResource(resourcesId);
BitmapFactory.Optionsoptions=newBitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeStream(ins,null,options);
floatsrcWidth=options.outWidth;
floatsrcHeight=options.outHeight;
intinSampleSize=1;
if(srcHeight>height||srcWidth>width){
if(srcWidth>srcHeight){
inSampleSize=Math.round(srcHeight/height);
}else{
inSampleSize=Math.round(srcWidth/width);
}
}
options.inJustDecodeBounds=false;
options.inSampleSize=inSampleSize;
returnBitmapFactory.decodeStream(ins,null,options);
}
BitmapFactory.decodeResource加载的图片可能会经过缩放,该缩放目前是放在Java层做的,效率比较低,而且需要消耗java层的内存。
因此,如果大量使用该接口加载图片,容易导致OOM错误
BitmapFactory.decodeStream不会对所加载的图片进行缩放,相比之下占用内存少,效率更高。
这两个接口各有用处,如果对性能要求较高,则应该使用decodeStream;如果对性能要求不高,且需要Android自带的图片自适应缩放功能,则可以使用decodeResource。
2.Assets资源加载方式:
/**
*获取缩放后的本地图片
*
*@paramfilePath文件路径,即文件名称
*@return
*/
publicstaticBitmapreadBitmapFromAssetsFile(Contextcontext,StringfilePath){
Bitmapimage=null;
AssetManageram=context.getResources().getAssets();
try{
InputStreamis=am.open(filePath);
image=BitmapFactory.decodeStream(is);
is.close();
}catch(IOExceptione){
e.printStackTrace();
}
returnimage;
}
4.从二进制数据读取图片
publicstaticBitmapreadBitmapFromByteArray(byte[]data,intwidth,intheight){
BitmapFactory.Optionsoptions=newBitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeByteArray(data,0,data.length,options);
floatsrcWidth=options.outWidth;
floatsrcHeight=options.outHeight;
intinSampleSize=1;
if(srcHeight>height||srcWidth>width){
if(srcWidth>srcHeight){
inSampleSize=Math.round(srcHeight/height);
}else{
inSampleSize=Math.round(srcWidth/width);
}
}
options.inJustDecodeBounds=false;
options.inSampleSize=inSampleSize;
returnBitmapFactory.decodeByteArray(data,0,data.length,options);
}
四、Bitmap|Drawable|InputStream|Byte[]之间进行转换
Drawable转化成Bitmap
publicstaticBitmapdrawableToBitmap(Drawabledrawable){
Bitmapbitmap=Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(),drawable.getOpacity()!
=PixelFormat.OPAQUE?
Bitmap.Config.ARGB_8888:
Bitmap.Config.RGB_565);
Canvascanvas=newCanvas(bitmap);
drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());
drawable.draw(canvas);
returnbitmap;
}
drawable的获取方式:
Drawabledrawable=getResources().getDrawable(R.draw