Android开发之超强图片工具类BitmapUtil完整实例
本文实例讲述了Android开发之超强图片工具类BitmapUtil。分享给大家供大家参考,具体如下:
说明:为了方便大家使用,本人把大家常用的图片处理代码集中到这个类里
使用了LruCache与SoftReference
/**
*图片加载及转化工具-----------------------------------------------------------------------延伸:一个Bitmap到底占用多大内存?系统给每个应用程序分配多大内存?Bitmap占用的内存为:像素总数
**每个像素占用的内存。在Android中,Bitmap有四种像素类型:ARGB_8888、ARGB_4444、ARGB_565、ALPHA_8,他们每个像素占用的字节数分别为4、2、2、1。因此,一个2000*1000的ARGB_8888
*类型的Bitmap占用的内存为2000*1000*4=8000000B=8MB。
*
*@authorchen.lin
*
*/
publicclassBitmapUtil{
/**
*1)软引用,已经不适合缓存图片信息,加载图片时会出现重叠的现象
*2)Android3.0(APILevel11)中,图片的数据会存储在本地的内存当中
*因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃,
*3)因为从Android2.3(APILevel9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,
这让软引用和弱引用变得不再可靠。
*
*/
privatestaticMap>imageCache=newHashMap>();
/**
*初始化lrucache,最少使用最先移除,LruCache来缓存图片,
*当存储Image的大小大于LruCache设定的值,系统自动释放内存,
*/
privatestaticLruCachemMemoryCache;
static{
finalintmemory=(int)(Runtime.getRuntime().maxMemory()/1024);
finalintcacheSize=memory/8;
mMemoryCache=newLruCache(cacheSize){
protectedintsizeOf(Stringkey,Bitmapvalue){
//returnvalue.getByteCount()/1024;
returnvalue.getHeight()*value.getRowBytes();
}
};
}
//---lrucache----------------------------------------------------
/**
*添加图片到lrucache
*
*@paramkey
*@parambitmap
*/
publicsynchronizedvoidaddBitmapToMemCache(Stringkey,Bitmapbitmap){
if(getBitmapFromMemCache(key)==null){
if(key!=null&bitmap!=null){
mMemoryCache.put(key,bitmap);
}
}
}
/**
*清除缓存
*/
publicvoidclearMemCache(){
if(mMemoryCache!=null){
if(mMemoryCache.size()>0){
mMemoryCache.evictAll();
}
mMemoryCache=null;
}
}
/**
*移除缓存
*/
publicsynchronizedvoidremoveMemCache(Stringkey){
if(key!=null){
if(mMemoryCache!=null){
Bitmapbm=mMemoryCache.remove(key);
if(bm!=null)
bm.recycle();
}
}
}
/**
*从lrucache里读取图片
*
*@paramkey
*@return
*/
publicBitmapgetBitmapFromMemCache(Stringkey){
if(key!=null){
returnmMemoryCache.get(key);
}
returnnull;
}
/**
*加载图片
*
*@paramcontext
*@paramresId
*@paramimageView
*/
publicvoidloadBitmap(Contextcontext,intresId,ImageViewimageView){
finalStringimageKey=String.valueOf(resId);
finalBitmapbitmap=getBitmapFromMemCache(imageKey);
if(bitmap!=null){
imageView.setImageBitmap(bitmap);
}else{
imageView.setImageResource(resId);
BitmapWorkerTasktask=newBitmapWorkerTask(context);
task.execute(resId);
}
}
/**
*任务类
*
*@ProjectApp_View
*@Packagecom.android.view.tool
*@authorchenlin
*@version1.0
*@Date2014年5月10日
*/
classBitmapWorkerTaskextendsAsyncTask{
privateContextmContext;
publicBitmapWorkerTask(Contextcontext){
mContext=context;
}
//在后台加载图片。
@Override
protectedBitmapdoInBackground(Integer...params){
finalBitmapbitmap=decodeSampledBitmapFromResource(mContext.getResources(),params[0],100,100);
addBitmapToMemCache(String.valueOf(params[0]),bitmap);
returnbitmap;
}
}
//--软引用---------------------------------------------------------
publicstaticvoidaddBitmapToCache(Stringpath){
//强引用的Bitmap对象
Bitmapbitmap=BitmapFactory.decodeFile(path);
//软引用的Bitmap对象
SoftReferencesoftBitmap=newSoftReference(bitmap);
//添加该对象到Map中使其缓存
imageCache.put(path,softBitmap);
}
publicstaticBitmapgetBitmapByPath(Stringpath){
//从缓存中取软引用的Bitmap对象
SoftReferencesoftBitmap=imageCache.get(path);
//判断是否存在软引用
if(softBitmap==null){
returnnull;
}
//取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空
Bitmapbitmap=softBitmap.get();
returnbitmap;
}
publicBitmaploadBitmap(finalStringimageUrl,finalImageCallBackimageCallBack){
SoftReferencereference=imageCache.get(imageUrl);
if(reference!=null){
if(reference.get()!=null){
returnreference.get();
}
}
finalHandlerhandler=newHandler(){
publicvoidhandleMessage(finalandroid.os.Messagemsg){
//加入到缓存中
Bitmapbitmap=(Bitmap)msg.obj;
imageCache.put(imageUrl,newSoftReference(bitmap));
if(imageCallBack!=null){
imageCallBack.getBitmap(bitmap);
}
}
};
newThread(){
publicvoidrun(){
Messagemessage=handler.obtainMessage();
message.obj=downloadBitmap(imageUrl);
handler.sendMessage(message);
}
}.start();
returnnull;
}
publicinterfaceImageCallBack{
voidgetBitmap(Bitmapbitmap);
}
//----其它工具----------------------------------------------------------------------------------
/**
*从网上下载图片
*
*@paramimageUrl
*@return
*/
privateBitmapdownloadBitmap(StringimageUrl){
Bitmapbitmap=null;
try{
bitmap=BitmapFactory.decodeStream(newURL(imageUrl).openStream());
returnbitmap;
}catch(Exceptione){
e.printStackTrace();
returnnull;
}
}
/**
*drawable转bitmap
*
*@paramdrawable
*@return
*/
publicstaticBitmapdrawable2Bitmap(Drawabledrawable){
Bitmapbitmap=Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(),
drawable.getOpacity()!=PixelFormat.OPAQUE?Bitmap.Config.ARGB_8888:Bitmap.Config.RGB_565);
Canvascanvas=newCanvas(bitmap);
//canvas.setBitmap(bitmap);
drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());
drawable.draw(canvas);
returnbitmap;
}
/**
*bitmap转drawable
*
*@parambm
*@return
*/
publicstaticDrawablebitmap2Drable(Bitmapbm){
returnnewBitmapDrawable(bm);
}
/**
*把字节数组通过BASE64Encoder转换成字符串
*
*@paramimage
*@return
*/
publicstaticStringgetBase64(byte[]image){
Stringstring="";
try{
BASE64Encoderencoder=newBASE64Encoder();
string=encoder.encodeBuffer(image).trim();
}catch(Exceptione){
e.printStackTrace();
}
returnstring;
}
/**
*把字节数据转换成Drawable
*
*@paramimgByte
*字节数据
*@return
*/
@SuppressWarnings("deprecation")
publicstaticDrawablebyte2Drawable(byte[]imgByte){
Bitmapbitmap;
if(imgByte!=null){
bitmap=BitmapFactory.decodeByteArray(imgByte,0,imgByte.length);
Drawabledrawable=newBitmapDrawable(bitmap);
returndrawable;
}
returnnull;
}
/**
*把图片转换成字节数组
*
*@parambmp
*@return
*/
publicstaticbyte[]bitmap2Byte(Bitmapbm){
BitmapoutBitmap=Bitmap.createScaledBitmap(bm,150,bm.getHeight()*150/bm.getWidth(),true);
if(bm!=outBitmap){
bm.recycle();
bm=null;
}
byte[]compressData=null;
ByteArrayOutputStreambaos=newByteArrayOutputStream();
try{
try{
outBitmap.compress(Bitmap.CompressFormat.PNG,100,baos);
}catch(Exceptione){
e.printStackTrace();
}
compressData=baos.toByteArray();
baos.close();
}catch(IOExceptione){
e.printStackTrace();
}
returncompressData;
}
/**
*缩放图片
*
*@parambitmap
*原图片
*@paramnewWidth
*@paramnewHeight
*@return
*/
publicstaticBitmapsetBitmapSize(Bitmapbitmap,intnewWidth,intnewHeight){
intwidth=bitmap.getWidth();
intheight=bitmap.getHeight();
floatscaleWidth=(newWidth*1.0f)/width;
floatscaleHeight=(newHeight*1.0f)/height;
Matrixmatrix=newMatrix();
matrix.postScale(scaleWidth,scaleHeight);
returnBitmap.createBitmap(bitmap,0,0,width,height,matrix,true);
}
/**
*缩放图片
*
*@parambitmapPath
*图片路径
*@return
*/
publicstaticBitmapsetBitmapSize(StringbitmapPath,floatnewWidth,floatnewHeight){
Bitmapbitmap=BitmapFactory.decodeFile(bitmapPath);
if(bitmap==null){
Logger.i("bitmap","bitmap------------>发生未知异常!");
returnnull;
}
intwidth=bitmap.getWidth();
intheight=bitmap.getHeight();
floatscaleWidth=newWidth/width;
floatscaleHeight=newHeight/height;
Matrixmatrix=newMatrix();
matrix.postScale(scaleWidth,scaleHeight);
returnBitmap.createBitmap(bitmap,0,0,width,height,matrix,true);
}
/**
*计算图片的缩放大小如果==1,表示没变化,==2,表示宽高都缩小一倍----------------------------------------------------------------------------
*inSampleSize是BitmapFactory.Options类的一个参数,该参数为int型,他的值指示了在解析图片为Bitmap时在长宽两个方向上像素缩小的倍数。inSampleSize的默认值和最小值为1(当小于1时,解码器将该值当做1来处理),
*且在大于1时,该值只能为2的幂(当不为2的幂时,解码器会取与该值最接近的2的幂)。例如,当inSampleSize为2时,一个2000*1000的图片,将被缩小为1000*500,相应地,它的像素数和内存占用都被缩小为了原来的1/4:
*
*@paramoptions
*@paramreqWidth
*@paramreqHeight
*@return
*/
publicstaticintcalculateInSampleSize(BitmapFactory.Optionsoptions,intreqWidth,intreqHeight){
//原始图片的宽高
finalintheight=options.outHeight;
finalintwidth=options.outWidth;
intinSampleSize=1;
if(height>reqHeight||width>reqWidth){
finalinthalfHeight=height/2;
finalinthalfWidth=width/2;
//在保证解析出的bitmap宽高分别大于目标尺寸宽高的前提下,取可能的inSampleSize的最大值
while((halfHeight/inSampleSize)>reqHeight&&(halfWidth/inSampleSize)>reqWidth){
inSampleSize*=2;
}
}
returninSampleSize;
}
/**
*根据计算出的inSampleSize生成Bitmap(此时的bitmap是经过缩放的图片)
*
*@paramres
*@paramresId
*@paramreqWidth
*@paramreqHeight
*@return
*/
publicstaticBitmapdecodeSampledBitmapFromResource(Resourcesres,intresId,intreqWidth,intreqHeight){
//首先设置inJustDecodeBounds=true来获取图片尺寸
finalBitmapFactory.Optionsoptions=newBitmapFactory.Options();
/**
*inJustDecodeBounds属性设置为true,decodeResource()方法就不会生成Bitmap对象,而仅仅是读取该图片的尺寸和类型信息:
*/
options.inJustDecodeBounds=true;
BitmapFactory.decodeResource(res,resId,options);
//计算inSampleSize的值
options.inSampleSize=calculateInSampleSize(options,reqWidth,reqHeight);
//根据计算出的inSampleSize来解码图片生成Bitmap
options.inJustDecodeBounds=false;
returnBitmapFactory.decodeResource(res,resId,options);
}
/**
*将图片保存到本地时进行压缩,即将图片从Bitmap形式变为File形式时进行压缩,
*特点是:File形式的图片确实被压缩了,但是当你重新读取压缩后的file为Bitmap是,它占用的内存并没有改变
*
*@parambmp
*@paramfile
*/
publicstaticvoidcompressBmpToFile(Bitmapbmp,Filefile){
ByteArrayOutputStreambaos=newByteArrayOutputStream();
intoptions=80;//个人喜欢从80开始,
bmp.compress(Bitmap.CompressFormat.JPEG,options,baos);
while(baos.toByteArray().length/1024>100){
baos.reset();
options-=10;
bmp.compress(Bitmap.CompressFormat.JPEG,options,baos);
}
try{
FileOutputStreamfos=newFileOutputStream(file);
fos.write(baos.toByteArray());
fos.flush();
fos.close();
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*将图片从本地读到内存时,进行压缩,即图片从File形式变为Bitmap形式
*特点:通过设置采样率,减少图片的像素,达到对内存中的Bitmap进行压缩
*@paramsrcPath
*@return
*/
publicstaticBitmapcompressImageFromFile(StringsrcPath,floatpixWidth,floatpixHeight){
BitmapFactory.Optionsoptions=newBitmapFactory.Options();
options.inJustDecodeBounds=true;//只读边,不读内容
Bitmapbitmap=BitmapFactory.decodeFile(srcPath,options);
options.inJustDecodeBounds=false;
intw=options.outWidth;
inth=options.outHeight;
intscale=1;
if(w>h&&w>pixWidth){
scale=(int)(options.outWidth/pixWidth);
}elseif(wpixHeight){
scale=(int)(options.outHeight/pixHeight);
}
if(scale<=0)
scale=1;
options.inSampleSize=scale;//设置采样率
options.inPreferredConfig=Config.ARGB_8888;//该模式是默认的,可不设
options.inPurgeable=true;//同时设置才会有效
options.inInputShareable=true;//。当系统内存不够时候图片自动被回收
bitmap=BitmapFactory.decodeFile(srcPath,options);
//returncompressBmpFromBmp(bitmap);//原来的方法调用了这个方法企图进行二次压缩
//其实是无效的,大家尽管尝试
returnbitmap;
}
/**
*判断照片的角度
*@parampath
*@return
*/
publicstaticintreadPictureDegree(Stringpath){
intdegree=0;
try{
ExifInterfaceexifInterface=newExifInterface(path);
intorientation=exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch(orientation){
caseExifInterface.ORIENTATION_ROTATE_90:
degree=90;
break;
caseExifInterface.ORIENTATION_ROTATE_180:
degree=180;
break;
caseExifInterface.ORIENTATION_ROTATE_270:
degree=270;
break;
}
}catch(IOExceptione){
e.printStackTrace();
}
returndegree;
}
/**
*Android根据设备屏幕尺寸和dpi的不同,给系统分配的单应用程序内存大小也不同,具体如下表
*
*屏幕尺寸DPI应用内存
*small/normal/largeldpi/mdpi16MB
*small/normal/largetvdpi/hdpi32MB
*small/normal/largexhdpi64MB
*small/normal/large400dpi96MB
*small/normal/largexxhdpi128MB
*-------------------------------------------------------
*xlargemdpi32MB
*xlargetvdpi/hdpi64MB
*xlargexhdpi128MB
*xlarge400dpi192MB
*xlargexxhdpi256MB
*/
}
更多关于Android相关内容感兴趣的读者可查看本站专题:《Android图形与图像处理技巧总结》、《Android开发入门与进阶教程》、《Android调试技巧与常见问题解决方法汇总》、《Android基本组件用法总结》、《Android视图View技巧总结》、《Android布局layout技巧总结》及《Android控件用法总结》
希望本文所述对大家Android程序设计有所帮助。