博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android BitmapFactory的OutOfMemoryError: bitmap ...
阅读量:6214 次
发布时间:2019-06-21

本文共 5594 字,大约阅读时间需要 18 分钟。

hot3.png

网上有很多解决android加载bitmap内存溢出的方法,搜了一圈做下整理总结。项目里需求是拍摄多图之后上传,部分手机会内存溢出

常用一种解决方法:即将载入的图片缩小,这种方式以牺牲图片的质量为代价。在BitmapFactory中有一个内部类BitmapFactory.Options,其中当options.inSampleSize值>1时,根据文档:

If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. (1 -> decodes full size; 2 -> decodes 1/4th size; 4 -> decode 1/16th size). Because you rarely need to show and have full size bitmap images on your phone. For manipulations smaller sizes are usually enough.

options.inSampleSize是以2的指数的倒数被进行放缩
现在问题是怎么确定inSampleSize的值?每张图片的放缩大小的比例应该是不一样的!这样的话就要运行时动态确定。在BitmapFactory.Options中提供了另一个成员inJustDecodeBounds。
设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。Android提供了一种动态计算的方法,见computeSampleSize().

public static int computeSampleSize(BitmapFactory.Options options,        int minSideLength, int maxNumOfPixels) {    int initialSize = computeInitialSampleSize(options, minSideLength,            maxNumOfPixels);     int roundedSize;    if (initialSize <= 8) {        roundedSize = 1;        while (roundedSize < initialSize) {            roundedSize <<= 1;        }    } else {        roundedSize = (initialSize + 7) / 8 * 8;    }     return roundedSize;} private static int computeInitialSampleSize(BitmapFactory.Options options,        int minSideLength, int maxNumOfPixels) {    double w = options.outWidth;    double h = options.outHeight;     int lowerBound = (maxNumOfPixels == -1) ? 1 :            (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));    int upperBound = (minSideLength == -1) ? 128 :            (int) Math.min(Math.floor(w / minSideLength),            Math.floor(h / minSideLength));     if (upperBound < lowerBound) {        return lowerBound;    }     if ((maxNumOfPixels == -1) &&            (minSideLength == -1)) {        return 1;    } else if (minSideLength == -1) {        return lowerBound;    } else {        return upperBound;    }}

以上只做为参考,我们只要用这函数即可,opts.inSampleSize = computeSampleSize(opts, -1, 128*128);

要点:

1、用decodeFileDescriptor()来生成bimap比decodeFile()省内存

FileInputStream is = = new FileInputStream(path);bmp = BitmapFactory.decodeFileDescriptor(is.getFD(), null, opts);

替换

Bitmap bmp = BitmapFactory.decodeFile(imageFile, opts);    imageView.setImageBitmap(bmp);

 

原因:

查看BitmapFactory的源码,对比一下两者的实现,可以发现decodeFile()最终是以流的方式生成bitmap 

decodeFile源码:

public static Bitmap decodeFile(String pathName, Options opts) {        Bitmap bm = null;        InputStream stream = null;        try {            stream = new FileInputStream(pathName);            bm = decodeStream(stream, null, opts);        } catch (Exception e) {            /*  do nothing.                If the exception happened on open, bm will be null.            */        } finally {            if (stream != null) {                try {                    stream.close();                } catch (IOException e) {                    // do nothing here                }            }        }        return bm;    }

 

decodeFileDescriptor的源码,可以找到native本地方法decodeFileDescriptor,通过底层生成bitmap

decodeFileDescriptor源码:

public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {        if (nativeIsSeekable(fd)) {            Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);            if (bm == null && opts != null && opts.inBitmap != null) {                throw new IllegalArgumentException("Problem decoding into existing bitmap");            }            return finishDecode(bm, outPadding, opts);        } else {            FileInputStream fis = new FileInputStream(fd);            try {                return decodeStream(fis, outPadding, opts);            } finally {                try {                    fis.close();                } catch (Throwable t) {/* ignore */}            }        }    } private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,Rect padding, Options opts);

2、当在android设备中载入较大图片资源时,可以创建一些临时空间,将载入的资源载入到临时空间中。

opts.inTempStorage = new byte[16 * 1024];

 

 

完整代码:

public static OutputStream decodeBitmap(String path) {		BitmapFactory.Options opts = new BitmapFactory.Options();		opts.inJustDecodeBounds = true;// 设置成了true,不占用内存,只获取bitmap宽高		BitmapFactory.decodeFile(path, opts);		opts.inSampleSize = computeSampleSize(opts, -1, 1024 * 800);		opts.inJustDecodeBounds = false;// 这里一定要将其设置回false,因为之前我们将其设置成了true		opts.inPurgeable = true;		opts.inInputShareable = true;		opts.inDither = false;		opts.inPurgeable = true;		opts.inTempStorage = new byte[16 * 1024];		FileInputStream is = null;		Bitmap bmp = null;		InputStream ins = null;		ByteArrayOutputStream baos = null;		try {			is = new FileInputStream(path);			bmp = BitmapFactory.decodeFileDescriptor(is.getFD(), null, opts); 			double scale = getScaling(opts.outWidth * opts.outHeight, 1024 * 600);			Bitmap bmp2 = Bitmap.createScaledBitmap(bmp,					(int) (opts.outWidth * scale),					(int) (opts.outHeight * scale), true);			bmp.recycle();			baos = new ByteArrayOutputStream();			bmp2.compress(Bitmap.CompressFormat.JPEG, 100, baos);			bmp2.recycle();			return baos;		} catch (FileNotFoundException e) {			e.printStackTrace();		} catch (IOException e) {			e.printStackTrace();		} finally {			try {				is.close();				ins.close();				baos.close();			} catch (IOException e) {				e.printStackTrace();			}			System.gc();		}		return baos;	}private static double getScaling(int src, int des) {/** * 目标尺寸÷原尺寸 sqrt开方,得出宽高百分比 */    double scale = Math.sqrt((double) des / (double) src);    return scale;}

转载于:https://my.oschina.net/jeffzhao/blog/80900

你可能感兴趣的文章
红帽mysql5.6源码编译安装过程
查看>>
mysql数据库密码重置
查看>>
面试中与HR的对决
查看>>
ClientProtocol协议之上定义的方法
查看>>
【hibernate】实体类创建的两种方式
查看>>
php源代码安装常见错误与解决办法
查看>>
linux-ldap的安装
查看>>
编译内核时bad register name `%dil'错误
查看>>
企业身份认证:风雨之后需绸缪
查看>>
实验:构建Samba共享服务器
查看>>
右击桌面反应慢
查看>>
Zabbix 3.2.6通过ODBC监控MySQL&Oracle
查看>>
mysql5.7的配置文件优化参考
查看>>
函数的调用
查看>>
线程常用操作方法
查看>>
超简单c语言小程序
查看>>
break跳出循环、continue结束本次循环、exit退出整个脚本
查看>>
JavaScript框架编程
查看>>
201903股票投资与实践入门二:政策选股与股市指标
查看>>
150809112 杨磊 学生管理系统
查看>>