标签:图片 内存 减少图片对内存的消耗 获取图片占用内存的大小
我们知道产生OOM的原因是内存的使用量持续增长,直到超过了内存使用上限。每部手机对应用程序的内存上限在出厂时就已经是固定的了,所以我们需要尽量控制内存的使用量不要超过这个内存阀值,才能避免OOM。具体的做法就是去减少对象对内存的消耗。而今天要讨论的主要是减少图片对内存的消耗,因为图片消耗内存比较大,大多数应用程序都会有大量图片的加载,产生OOM往往也会发生在加载大量图片的时候。所以对图片占用内存的管理优化是很有必要的。但要记住的一点是,在内存的持续增长中,图片确实是其中一个很重量级的角色,但不是唯一的诱因,比如不好的代码写法导致产生大量对象或者内存泄露。这里说的只是降低图片对内存的消耗,谈不上解决OOM,因为图片一多,还是会产生OOM,只是推迟了问题产生的时间而已。
一、从网上获取到的图片的大小和图片占用的内存是不一样的
比如在我们图片列表里要加载这样一张图片:http://img.my.csdn.net/uploads/201407/26/1406383299_1976.jpg 打开链接查看图片属性
看到大小是23.44KB,尺寸即宽高是240px
x 240px。那当程序解码这张图片时申请的内存大小也是23.44KB吗?这里要注意的是,我们所要加载的网络图片的大小并不是Bitmap对象占用的内存大小!图片在内存中的大小的计算方式是:图片长(px) x 图片宽(px) x 单位像素占用的字节数。这张图片网页上显示的大小是24007字节,23.44KB,但是读到内存中(使用ARGB_8888颜色类型),他占用的内存大小是240x240x4=230400字节,225KB。
二、怎样查看或获取图片占用的内存大小?
图片的长 x图片的宽 x 单位像素占用的字节数
Android中不同的图片格式,他的单位像素占用的字节数不同。图片格式总共有四种:
Bitmap.Config = ALPHA_8 一个像素占1个字节
Bitmap.Config = ARGB_4444 一个像素占2个字节
Bitmap.Config = ARGB_8888 一个像素占4个字节(默认)
Bitmap.Config = ARGB_565 一个像素占2个字节
@TargetApi(Build.VERSION_CODES.KITKAT) public int getBitmapSize(Bitmap bitmap){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){// API 19 Android 4.4 return bitmap.getAllocationByteCount(); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1){// API 12 Android 3.1 return bitmap.getByteCount(); } return bitmap.getRowBytes() * bitmap.getHeight(); }Android已经为我们提供了返回图片占用内存大小的方法了,调用该方法和我们通过计算得到的结果是一致的。
private Bitmap loadBitmap(String imageUrl) { HttpURLConnection connection = null; Bitmap bitmap = null; try { URL url = new URL(imageUrl); connection = (HttpURLConnection) url.openConnection(); BitmapFactory.Options options = new BitmapFactory.Options(); //防止第一次解析时对图片的内存分配 options.inJustDecodeBounds = true; //第一次解析 BitmapFactory.decodeStream(connection.getInputStream(), null, options); //decodeStream不能重复解析同一个网络流的inputStream,需要重新打开一次inputStream connection.disconnect(); connection = (HttpURLConnection) url.openConnection(); //获取图片的缩放比例 options.inSampleSize = calculateInSampleSize(options,100, 100); //将options.inJustDecodeBounds的值设回false,为了第二次解析能够正常分配内存 options.inJustDecodeBounds = false; //第二次解析,此时图片的内存会按照压缩后的图片宽高去分配 bitmap = BitmapFactory.decodeStream(connection.getInputStream(), null, options); L.d("loadBitmap url = "+imageUrl); L.d("该图占用内存 = "+getBitmapSize(bitmap)+"bytes, "+(getBitmapSize(bitmap)/1024)+"KB"+", width = "+bitmap.getWidth()+", height = "+bitmap.getHeight()+", config = "+bitmap.getConfig().name()); return bitmap; } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { if (connection != null){ connection.disconnect(); } } return bitmap; } private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { int width = options.outWidth;//原图的宽 int height = options.outHeight;//原图的高 int inSampleSize = 1; if (height > reqHeight || width > reqWidth){ //计算出原图宽高和目标宽高的比例——缩小几倍 int heightRadio = Math.round((float)height / (float)reqHeight); int widthRadio = Math.round((float)width / (float)reqWidth); //选择宽和高中最小的比例作为inSampleSize的值,可以保证最终图片的宽和高一定都会大于等于目标的宽和高 inSampleSize = heightRadio < widthRadio ? heightRadio : widthRadio; } return inSampleSize; } @TargetApi(Build.VERSION_CODES.KITKAT) public int getBitmapSize(Bitmap bitmap){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){// API 19 Android 4.4 return bitmap.getAllocationByteCount(); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1){// API 12 Android 3.1 return bitmap.getByteCount(); } return bitmap.getRowBytes() * bitmap.getHeight(); }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:图片 内存 减少图片对内存的消耗 获取图片占用内存的大小
原文地址:http://blog.csdn.net/aliaooooo/article/details/47256337