关于OutOfMemoryError问题,偶尔出现,还是得去解决一下,最近看到个不错的解决方式:来自于:/article/3555123.html常用一种解决方法:即将载入的图片缩小,这种方式以牺牲图片的质量为代价。在BitmapFactory中有一个内部类BitmapFactory.Options,其中当options.inSampleSize值>1时,根据文档:Ifsettoavalue>1,requeststhedecodertosubsampletheoriginalimage,returningasmallerimagetosavememory.(1->decodesfullsize;2->decodes1/4thsize;4->decode1/16thsize).Becauseyourarelyneedtoshowandhavefullsizebitmapimagesonyourphone.Formanipulationssmallersizesareusuallyenough.options.inSampleSize是以2的指数的倒数被进行放缩现在问题是怎么确定inSampleSize的值?每张图片的放缩大小的比例应该是不一样的!这样的话就要运行时动态确定。在BitmapFactory.Options中提供了另一个成员inJustDecodeBounds。设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。Android提供了一种动态计算的方法,见computeSampleSize().01 | public static int computeSampleSize(BitmapFactory.Optionsoptions, |
02 | int minSideLength, int maxNumOfPixels){ |
03 | int initialSize=computeInitialSampleSize(options,minSideLength, |
09 | while (roundedSize<initialSize){ |
13 | roundedSize=(initialSize+ 7 )/ 8 * 8 ; |
19 | private static int computeInitialSampleSize(BitmapFactory.Optionsoptions, |
20 | int minSideLength, int maxNumOfPixels){ |
21 | double w=options.outWidth; |
22 | double h=options.outHeight; |
24 | int lowerBound=(maxNumOfPixels==- 1 )? 1 : |
25 | ( int )Math.ceil(Math.sqrt(w*h/maxNumOfPixels)); |
26 | int upperBound=(minSideLength==- 1 )? 128 : |
27 | ( int )Math.min(Math.floor(w/minSideLength), |
28 | Math.floor(h/minSideLength)); |
30 | if (upperBound<lowerBound){ |
34 | if ((maxNumOfPixels==- 1 )&& |
37 | } else if (minSideLength==- 1 ){ |
以上只做为参考,我们只要用这函数即可,opts.inSampleSize=computeSampleSize(opts,-
1
,
128
*
128
);
要点:1、用decodeFileDescriptor()来生成bimap比decodeFile()省内存1 | FileInputStreamis== new FileInputStream(path); |
2 | bmp=BitmapFactory.decodeFileDescriptor(is.getFD(), null ,opts); |
替换1 | Bitmapbmp=BitmapFactory.decodeFile(imageFile,opts); |
2 | imageView.setImageBitmap(bmp); |
原因:查看BitmapFactory的源码,对比一下两者的实现,可以发现decodeFile()最终是以流的方式生成bitmapdecodeFile源码:01 | public static BitmapdecodeFile(StringpathName,Optionsopts){ |
03 | InputStreamstream= null ; |
05 | stream= new FileInputStream(pathName); |
06 | bm=decodeStream(stream, null ,opts); |
09 | Iftheexceptionhappenedonopen,bmwillbenull. |
decodeFileDescriptor的源码,可以找到native本地方法decodeFileDescriptor,通过底层生成bitmapdecodeFileDescriptor源码:01 | public static BitmapdecodeFileDescriptor(FileDescriptorfd,RectoutPadding,Optionsopts){ |
02 | if (nativeIsSeekable(fd)){ |
03 | Bitmapbm=nativeDecodeFileDescriptor(fd,outPadding,opts); |
04 | if (bm== null &&opts!= null &&opts.inBitmap!= null ){ |
05 | throw new IllegalArgumentException( "Problemdecodingintoexistingbitmap" ); |
07 | return finishDecode(bm,outPadding,opts); |
09 | FileInputStreamfis= new FileInputStream(fd); |
11 | return decodeStream(fis,outPadding,opts); |
15 | } catch (Throwablet){ /*ignore*/ } |
20 | private static native BitmapnativeDecodeFileDescriptor(FileDescriptorfd,Rectpadding,Optionsopts); |
2、当在android设备中载入较大图片资源时,可以创建一些临时空间,将载入的资源载入到临时空间中。1 | opts.inTempStorage= new byte [ 16 * 1024 ]; |
?完整代码:viewsourceprint?01 | public static OutputStreamdecodeBitmap(Stringpath){ |
03 | BitmapFactory.Optionsopts= new BitmapFactory.Options(); |
04 | opts.inJustDecodeBounds= true ; //设置成了true,不占用内存,只获取bitmap宽高 |
05 | BitmapFactory.decodeFile(path,opts); |
06 | opts.inSampleSize=computeSampleSize(opts,- 1 , 1024 * 800 ); |
08 | opts.inJustDecodeBounds= false ; //这里一定要将其设置回false,因为之前我们将其设置成了true |
10 | opts.inInputShareable= true ; |
13 | opts.inTempStorage= new byte [ 16 * 1024 ]; |
14 | FileInputStreamis= null ; |
17 | ByteArrayOutputStreambaos= null ; |
19 | is= new FileInputStream(path); |
20 | bmp=BitmapFactory.decodeFileDescriptor(is.getFD(), null ,opts); double scale=getScaling(opts.outWidth*opts.outHeight, 1024 * 600 ); |
21 | Bitmapbmp2=Bitmap.createScaledBitmap(bmp, |
22 | ( int )(opts.outWidth*scale), |
23 | ( int )(opts.outHeight*scale), true ); |
25 | baos= new ByteArrayOutputStream(); |
26 | bmp2.compress(Bitmap.CompressFormat.JPEG, 100 ,baos); |
29 | } catch (FileNotFoundExceptione){ |
46 | private static double getScaling( int src, int des){ |
48 | *目标尺寸÷原尺寸sqrt开方,得出宽高百分比 |
50 | double scale=Math.sqrt(( double )des/( double )src); |
==============================================================================================================以上来自于转载:接下来来点自己的这块写的代码:/***根据filename获取bitmap**@paramheight*@paramwidth*/publicstaticBitmapgetBitmapByName(Stringfilename,intwidth,intheight){Bitmapbitmap=null;if(!hasSDcard()){returnbitmap;}Filefile=newFile(filename);FileInputStreamfs=null;try{fs=newFileInputStream(file);}catch(FileNotFoundExceptione){e.printStackTrace();}if(!file.exists()||!file.isFile()){returnbitmap;}try{Bitmapbmp=null;Optionsopts=newBitmapFactory.Options();opts.inJustDecodeBounds=true;bmp=BitmapFactory.decodeFile(file.getPath(),opts);//计算图片缩放比例finalintminSideLength=Math.min(width,height);opts.inSampleSize=computeSampleSize(opts,minSideLength,width*height);opts.inJustDecodeBounds=false;opts.inInputShareable=true;opts.inPurgeable=true;opts.inDither=false;opts.inPurgeable=true;opts.inTempStorage=newbyte[16*1024];//bitmap=BitmapFactory.decodeFile(file.getPath(),opts);if(fs!=null){bmp=BitmapFactory.decodeFileDescriptor(fs.getFD(),null,opts);bitmap=Bitmap.createBitmap(bmp);}//---将图片占有的内存资源释放bmp=null;//bmp.recycle();//这里的回收,在程序里有点问题System.gc();}catch(Exceptione){//TODOAuto-generatedcatchblockLog.e("getbitmap","exception");e.printStackTrace();bitmap=null;}finally{if(fs!=null){try{fs.close();}catch(IOExceptione){e.printStackTrace();}}}returnbitmap;}//--------------------------------------/***计算缩放的比例***/privatestaticintcomputeSampleSize(BitmapFactory.Optionsoptions,intminSideLength,intmaxNumOfPixels){intinitialSize=computeInitialSampleSize(options,minSideLength,maxNumOfPixels);introundedSize;if(initialSize<=8){roundedSize=1;while(roundedSize<initialSize){roundedSize<<=1;}}else{roundedSize=(initialSize+7)/8*8;}returnroundedSize;}privatestaticintcomputeInitialSampleSize(BitmapFactory.Optionsoptions,intminSideLength,intmaxNumOfPixels){doublew=options.outWidth;doubleh=options.outHeight;intlowerBound=(maxNumOfPixels==-1)?1:(int)Math.ceil(Math.sqrt(w*h/maxNumOfPixels));intupperBound=(minSideLength==-1)?128:(int)Math.min(Math.floor(w/minSideLength),Math.floor(h/minSideLength));if(upperBound<lowerBound){//returnthelargeronewhenthereisnooverlappingzone.returnlowerBound;}if((maxNumOfPixels==-1)&&(minSideLength==-1)){return1;}elseif(minSideLength==-1){returnlowerBound;}else{returnupperBound;}}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理