android 加载图片oom异常
来源:互联网 发布:nginx 缓存mp4文件 编辑:程序博客网 时间:2024/04/27 13:38
一、OOM异常是什么?产生OOM异常的原因
OOM(Out Of Memory--内存不够用了)
a、计算图片占用的内存大小:
1、 占用内存 = 图片的长度 * 图片的宽度 * 单位像素占用的字节数;
2、 单位像素占用的字节数是由BitmapFactory.Options的inPreferredConfig变量的值决定的:
A(alpha)--透明度,R(red)--红色,G(green)--绿色,B(blue)--蓝色,即三原色;如一张图片是720*1080,ARGB是一
种色彩模式:
① Bitmap.Config.ALPHA_8: 此时图片就只有alpha值,一个像素就只占用一个字节(8代表的是这个透明度占用8
位,即一个字节),图片占用的内存大小:720*1080*1(字节)
② Bitmap.Config.ARGB_4444: 即A、R、G、B 各占四个bit,总共就是4*4=16个bit= 2(字节),这种格式的图片看
起来质量很差,已经不再使用, 图片占用的内存大小:720*1080*2(字节)
③ Bitmap.Config.ALPHA_8888: 即A、R、G、B各占8个bit,总共就是4*8=32bit = 4(字节),这是一种高质量的图
片,android手机上Bitmap默认的格式,图片占用的内存:720*1080*4(字节)
④ Bitmap.Config.RGB_565 : 即 R、G、B 分别占用5、6、5个bit,总共:5+6+5=16bit=2(字节),这种格式的图片,
不支持透明和半透明,图片质量也达到了效果,且占用内存相对来说较小,图片占用内存:720*1080*2(字节)
b、 一个应用程序,android系统一般会为它分配16MB的内存大小,,例如:三星s4后置摄像头像素1300万,则拍照后,照片
的大小就是1300万*4(字节)(假设单位像素的字节数按4个字节),即49.6MB,远远超过了android系统分配给这个应
用的内存,且这16MB不仅仅是用来存储图片的,所以如果不处理图片,直接加载图片的话,就会出现OOM异常。这是
android开发中最常见的OOM异常。
二、解决OOM异常的方法:
a、改变图片的大小,即缩小图片,缩小图片的方法:
方法一:利用Matrix来缩小图片
public Bitmap zoomBitmap(Bitmap bitmap) { //获得Bitmap的高和宽 int bmpWidth = bitmap.getWidth(); int bmpHeight = bitmap.getHeight(); //这边假设imageView的宽和高是一样的 int imageViewHeight = imageViewWidth; //设置缩小比例,imageViewWidth 就是我们需要的宽度 double scale = (double) imageViewWidth / bmpWidth; double scaleH = (double) imageViewHeight/bmpHeight; //为了保证图片可以显示完全 if (scale>scaleH){ scale = scaleH; } Log.e("缩放比例:", "scale = " + scale); //计算出长宽要缩放的比例 float scaleWidth = (float) (1 * scale); float scaleHeight = (float) (1 * scale); //产生resize后的Bitmap对象 Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); Bitmap resizeBmp = null; resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bmpWidth, bmpHeight, matrix, true); Log.e("缩放后的图片的宽度:bitmapWidth=", "" + resizeBmp.getWidth()); //修改色彩模式 Bitmap zoomBitmap = resizeBmp.copy (Bitmap.Config.RGB_565,false); return zoomBitmap; }优点:可以按任何比例来缩放,即缩放比例可以是小数;而Options.inSampleSize 只能是整数。
缺点:会耗费很大的内存,因为缩放后的图片的色彩模式是ARGB_8888,每个像素单位就是4个字节了;
解决办法:修改色彩模式,如代码所示,这样虽然会生成一个Bitmap对象,但是总的消耗的内存还是减小的。
方法二:利用BitmapFactory.Options进行缩放:
private Bitmap getimage(String srcPath) { BitmapFactory.Options newOpts = new BitmapFactory.Options(); //开始读入图片,此时把options.inJustDecodeBounds 设回true了 newOpts.inJustDecodeBounds = true; BitmapFactory.decodeFile(srcPath, newOpts);//此时返回bitmap为空,只有一些图片大小等信息;
//这时候设置false ,返回的bitmap就不是空的了
newOpts.inJustDecodeBounds = false; int w = newOpts.outWidth; int h = newOpts.outHeight;
//imageViewWidth和imageViewHeight是我们希望的宽和高 int hh = imageViewWidth; int ww = imageViewWidth;
//缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 int be = 1;//be=1表示不缩放 if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放 be = (int) (newOpts.outWidth / ww); } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放 be = (int) (newOpts.outHeight / hh); }
//be不能是小数,必须是整型的 if (be <= 0) be = 1; newOpts.inSampleSize = be;//设置缩放比例 //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 bitmap = BitmapFactory.decodeFile(srcPath, newOpts); //直接返回,不用质量压缩也可以展示 return bitmap; }优点:可以通过options.inJustDecodeBounds=true,来节省内存的开销
缺点:options.inSampleSize只能是2的整数次幂,如果不是的话,就向下取最大的2的整数次幂
b、改变图片的质量,但是这样会造成图片看起来不清晰:
private Bitmap compressQualityImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); //100代表不压缩图片,把图片保存到baos中 image.compress(Bitmap.CompressFormat.JPEG, 100, baos); int options = 100;
//500KB 就是我们能用的最大内存空间了 while (baos.toByteArray().length / 1024 > 500) { //清空baos baos.reset(); options -= 10; if (options < 0) { break; } image.compress(Bitmap.CompressFormat.JPEG, options, baos); } //把压缩后的图片放在inBm中 ByteArrayInputStream inBm = new ByteArrayInputStream(baos.toByteArray()); //生成图片 Bitmap bitmap = BitmapFactory.decodeStream(inBm, null, null); return bitmap; }c、目前我知道的最优方案,实际应用中也高高的
分析:当我们使用BitmapFactory.decodeResource()、decodeFile()等方法时,这些方法最终都是通过java层的
createBitmap()方法来生成Bitmap的,这样就会消耗很多的内存;因此我们如果用BitmapFactory.decodeStream()来生成一个Bitmap对象时,无需调用java层的
createBitmap()方法,而是直接调用JNI的nativeDecodeAsset()方法来完成,节省很多的内存空间,如果再加上图片的Config(色彩模式)参数(最好用
Bitmap.Config.RGB_565)这样就更加有效地减少的内存的开销。
代码:
/** *相对来说最优生成Bitmap的方法 * @param context * @param resId 图片的id,一般在drawable下的图片,代码中也有如何根据图片路径来构造流 * @return */ public static Bitmap readBitmap(Context context, int resId) { BitmapFactory.Options opt = new BitmapFactory.Options(); //最低位的配置 opt.inPreferredConfig = Bitmap.Config.RGB_565; //inPurgeable设为true的话表示使用BitmapFactory创建的Bitmap用于存储Pixel的内存空间在系统内存不足时可以被回收 opt.inPurgeable = true; //是否深拷贝??? opt.inInputShareable = true; //1、drawable下的图片构造流的方法 InputStream is = context.getResources().openRawResource(resId); //2、根据路径构造流的方法 try { String picturePath = ".........."; File file = new File(picturePath); InputStream inputStream = new FileInputStream(file); }catch (Exception e){ e.printStackTrace(); } return BitmapFactory.decodeStream(is, null, opt); }d、注意:只用一次的Bitmap的记着回收,代码如下:
if(!bitmap.isRecycled()){ bitmap.recycle();//回收图片所占的内存 bitmap = null; System.gc();//提醒系统及时回收 }
参考资料:http://www.cnblogs.com/plokmju/p/android_loadbigimage.html
- android 加载图片oom异常
- Android 图片加载Bit地图 OOM异常解决方法
- Android 图片加载Bit地图 OOM异常解决方法
- Android 加载打图片出现OOM异常的处理方式
- Android高效加载OOM异常避免OOM
- android图片加载之OOM
- Android-加载图片OOM总结
- android 图片加载,OOM 问题
- android加载图片OOM问题
- android加载图片出现OOM
- Android加载大图片OOM异常解决
- Android加载大图片OOM异常解决
- 【OOM】Android加载大图片OOM异常解决
- Android加载大图片时的OOM异常及解决(图片的二次采样)
- Android在加载图片时, BitmapFactory.decodeStream(is)代码报出OOM异常问题解决
- android中加载图片时出现oom
- Android 图片加载Bitmap OOM错误解决办法
- Android 图片加载Bitmap OOM错误解决办法
- 12864带字库显示屏画图程序
- 黑马程序员—— 8,关于异常Exception的知识点
- 对文件I/0缓冲的认识
- 杭电1025
- 详解 Android 的 Activity 组件
- android 加载图片oom异常
- JVM内存模型
- 复制图片的4种方式(copy图片只能用字节流对象)
- 剑指offer_面试题6_重建二叉树(分解步骤,逐个击破)
- jQuery.extend与jQuery.fn.extend
- 【C#】26. Enigma 模拟器
- 12864带字库显示屏滚屏显示
- Android 四大组件之ContentProvider
- I/O复用-每次调用select()前都要重新设置一下待检测的描述字