一、遇到问题:       Android的开发的小伙伴在项目中有时遇到多张大图片的加载,图片的类型是多种多样,不同大小。但是大多数的图片都是高分辨率,总体来说,远远大于我们要展示的容器ImageView。有些就认为,图片的分辨率高和图片太大顶多就消耗更多流量而已,其实不是的,其实我们编程的运用程序是有内存限制的。程序的内存如果过高就会出现OOM异常。我们先在应用程序中编程以下代码,观察一下现象:
//最大从虚拟机能挖过来的内存long maxMemory = Runtime.getRuntime().maxMemory()/1024/1024;//挖过来的内存没用上称之为freeMemory,基本都是要多少挖它多少。long freeMemory = Runtime.getRuntime().freeMemory()/1024/1024;//已经从操纵系统那里挖过来的内存大小,也就是java虚拟机这个进程当时所占用的所有内存long totalMemory = Runtime.getRuntime().totalMemory()/1024/1024;
打印出:

     从这个打印信息,可以看出,我们的应用程序的内存是多么宝贵的!所以在我们展示图片的时候,对图片进行处理,处理一般包括两种:图片质量压缩、图片大小压缩。在不要求高分辨率的需求下,可以对图片进行质量压缩。至于图片大小压缩,可以根据ImageView控件的展示图片长宽,将图片压缩至相近的距离,不但不会影响显示的效果,而且有效的减少OOM。接下来我们看一看,怎么对一张大图片的处理呢?
二、单张大图片压缩(质量和比例)      查看api文档,Android图片Bitmap对象是用BitmapFactory工具类中多种解析方法创建的。 创建的方式大概分为: 1)字节数组解析方式
2)SD卡文件中加载 解析 方式
3)资源中文件加载 解析 方式
4)网络中加载流的解析方式
           这些方法会尝试为已经构建的bitmap分配内存,这时就会很容易导致OOM出现。为此每一种解析方法都提供了一个可选的BitmapFactory.Options参数,将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存,返回值也不再是一个Bitmap对象,而是null。虽然Bitmap是null了,但是BitmapFactory.Options的outWidth、outHeight和outMimeType属性都会被赋值。这个技巧让我们可以在加载图片之前就获取到图片的长宽值和MIME类型,从而根据情况对图片进行压缩。
/** * 从SD卡中获取图片并且比例压缩 * @param path 路径 * @param mHeight 自定义高度 * @param mWidth 自定义宽度 * @return */public static Bitmap getBitmapFromSDCard(String path, int mHeight, int mWidth){    BitmapFactory.Options options = new BitmapFactory.Options();    options.inJustDecodeBounds = true;    BitmapFactory.decodeFile(path, options);        //计算比例值    options.inSampleSize = calculateInSampleSize(options,mHeight,mWidth);    options.inJustDecodeBounds = false;    return BitmapFactory.decodeFile(path, options);}/** * 计算压缩比例值inSampleSize * @param options 压缩的参数设置 * @param mHeight 想要的高度 * @param mWidth 想要的宽度 * @return */public static int calculateInSampleSize(BitmapFactory.Options options, int mHeight, int mWidth){    //原尺寸大小    int yHeight = options.outHeight;    int yWidth = options.outWidth;    int inSampleSize = 1;    //如果宽度大的话根据宽度固定大小缩放    if (yWidth > yHeight && yWidth > mWidth) {        inSampleSize = (int) (yWidth / mWidth);    }    //如果高度高的话根据宽度固定大小缩放    else if (yWidth < yHeight && yHeight > mHeight)    {        inSampleSize = (int) (yHeight / mHeight);    }    if (inSampleSize <= 0)        inSampleSize = 1;    return inSampleSize;}
     观察代码,可以看出,先后解析了两次图片,首先options.inJustDecodeBounds true以后,BitmapFactory解析一次图片,将图片的得到的option传入到方法calculateInSampleSize方法中,在方法中可以根据ImageView控件的长宽对图片进行压缩,计算出合适的inSamplesize值,最后 options.inJustDecodeBounds 设置 false以后,在对图片解析一次,这时的图片的比例值 inSamplesize正是我们计算出来的值。      调用getBitmapFromSDCard方法即可得到压缩过的Bitmap对象了。
//得到100*100图片mImageView.setImageBitmap(BitMapUtil.getBitmapFromSDCard(path,100,100));
     上面的这样做已经可以图片的比例压缩,至于有需要对图片质量压缩的可以参照一下代码。
/** * 图片质量压缩(质量参数) * @param image * @param quality 质量参数 百分之多少 例如:0.6  0.7 * @return */public static Bitmap compressImage(Bitmap image, float quality){    ByteArrayOutputStream baos = new ByteArrayOutputStream();    image.compress(Bitmap.CompressFormat.JPEG, (int)quality*100, baos);    ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中    return BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片}
     掌握了以上方法,不管是要在程序中加载超大图片,还是要加载大量图片,都不用担心OOM的问题了!如果有出错或者需要改进的地方,欢迎指点或者交流。













更多相关文章

  1. 第九章:Android中的数据存取
  2. android动态增加控件时控制样式的方法
  3. Android(安卓)滑动绘制流程探究 系统是如何提高滑动性能?
  4. 进程(一) 1.1 Android中异步处理大杀器——AsyncTask
  5. 像写Flutter一样开发Android原生应用
  6. Android上超级好用的前端调试方法(adb reverse)
  7. [Android]-图片JNI(C++\Java)高斯模糊的实现与比较
  8. Android(安卓)入门第十讲02-广播(广播概述,使用方法(系统广播,自定义
  9. Android(java方法)上实现mp4的分割和拼接 (二)

随机推荐

  1. Android api,Android SDK
  2. android后台进程隐藏手段
  3. ch026 Android Socket
  4. Uyghur Android
  5. android的布局练习
  6. Fragment 中的onConfigurationChanged 在
  7. android中重要的知识点
  8. android访问SD卡的权限
  9. android 选中效果xml文件
  10. android 设置主页面的方式