在通过BitmapFactory.decodeFile(String path)方法将突破转成Bitmap时,遇到大一些的图片,我们经常会遇到OOM(Out Of Memory)的问题。怎么避免它呢? 这就用到了我们上面提到的BitmapFactory.Options这个类。

BitmapFactory.Options这个类,有一个字段叫做 inJustDecodeBounds 。SDK中对这个成员的说明是这样的: If set to true, the decoder will return null (no bitmap), but the out… 也就是说,如果我们把它设为true,那么BitmapFactory.decodeFile(String path, Options opt)并不会真的返回一个Bitmap给你,它仅仅会把它的宽,高取回来给你,这样就不会占用太多的内存,也就不会那么频繁的发生OOM了。

示例代码如下:

  1. BitmapFactory.Options options = new BitmapFactory.Options();
  2. options.inJustDecodeBounds = true;
  3. Bitmap bmp = BitmapFactory.decodeFile(path, options);

复制代码

这段代码之后,options.outWidth 和 options.outHeight就是我们想要的宽和高了。

有了宽,高的信息,我们怎样在图片不变形的情况下获取到图片指定大小的缩略图呢? 比如我们需要在图片不变形的前提下得到宽度为200的缩略图。 那么我们需要先计算一下缩放之后,图片的高度是多少

  1. int height = options.outHeight * 200 / options.outWidth;
  2. options.outWidth = 200;
  3. options.outHeight = height;
  4. options.inJustDecodeBounds = false;
  5. Bitmap bmp = BitmapFactory.decodeFile(path, options);
  6. image.setImageBitmap(bmp);

复制代码

这样虽然我们可以得到我们期望大小的ImageView 但是在执行BitmapFactory.decodeFile(path, options);时,并没有节约内存。要想节约内存,还需要用到BitmapFactory.Options这个类里的 inSampleSize 这个成员变量。 我们可以根据图片实际的宽高和我们期望的宽高来计算得到这个值。

  1. inSampleSize = options.outWidth / 200;

另外,为了节约内存我们还可以使用下面的几个字段:

  1. options.inPreferredConfig = Bitmap.Config.ARGB_4444;    // 默认是Bitmap.Config.ARGB_8888
  2. options.inPurgeable = true;
  3. options.inInputShareable = true;

BitmapFactory.Options.inSampleSize

设置恰当的inSampleSize可以使BitmapFactory分配更少的空间以消除该错误。inSampleSize的具体含义请参考SDK文档。例如:

BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);

设置恰当的inSampleSize是解决该问题的关键之一。BitmapFactory.Options提供了另一个成员inJustDecodeBounds。

BitmapFactory.Options opts = new BitmapFactory.Options();opts.inJustDecodeBounds = true;Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);

设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。

查看Android源码,我们得知,为了得到恰当的inSampleSize,Android提供了一种动态计算的方法。

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 the larger one when there is no overlapping zone.return lowerBound;}if ((maxNumOfPixels == -1) && (minSideLength == -1)) {return 1;} else if (minSideLength == -1) {return lowerBound;} else {return upperBound;}
} 使用该算法,就可动态计算出图片的inSampleSize。BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageFile, opts);
opts.inSampleSize = computeSampleSize(opts, -1, 128*128);
opts.inJustDecodeBounds = false;
try {bmp = BitmapFactory.decodeFile(imageFile, opts);imageView.setImageBitmap(bmp);
} catch (OutOfMemoryError err) {
}

源代码如下:

    public static Bitmap createImageThumbnail(String filePath){Bitmap bitmap = null;BitmapFactory.Options opts = new BitmapFactory.Options();opts.inJustDecodeBounds = true;BitmapFactory.decodeFile(filePath, opts);opts.inSampleSize = computeSampleSize(opts, -1, 128*128);opts.inJustDecodeBounds = false;try {bitmap = BitmapFactory.decodeFile(filePath, opts);}catch (Exception e) {// TODO: handle exception
        }return bitmap;}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 the larger one when there is no overlapping zone.return lowerBound;}if ((maxNumOfPixels == -1) && (minSideLength == -1)) {return 1;} else if (minSideLength == -1) {return lowerBound;} else {return upperBound;}}

项目实战代码:

/*** 不full load图片,先根据一定的算法缩小再load* * @param path* @return*/public static Bitmap loadBitmapFromFile(String path, int thumbWidth, int thumbHeight) {Bitmap bmp = null;BitmapFactory.Options opts = new BitmapFactory.Options();/** 设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。* 有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize*/opts.inJustDecodeBounds = true;BitmapFactory.decodeFile(path, opts);opts.inSampleSize = calculateInSampleSize(opts, thumbWidth, thumbHeight);//这里一定要将其设置回false,因为之前我们将其设置成了true     opts.inJustDecodeBounds = false;try {bmp = BitmapFactory.decodeFile(path, opts);} catch (OutOfMemoryError e) {Logger.e(TAG, e.getMessage());}return bmp;}//计算图片的缩放值public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {final int height = options.outHeight;final int width = options.outWidth;int inSampleSize = 1;if (height > reqHeight || width > reqWidth) {final int heightRatio = Math.round((float) height / (float) reqHeight);final int widthRatio = Math.round((float) width / (float) reqWidth);inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;}return inSampleSize;}/*** 不full load图片,先根据一定的算法缩小再load* * @param path* @return*/public static Bitmap loadBitmapFromFile(String path) {Bitmap bmp = null;BitmapFactory.Options opts = new BitmapFactory.Options();/** 设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。* 有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize*/opts.inJustDecodeBounds = true;BitmapFactory.decodeFile(path, opts);opts.inSampleSize = computeSampleSize(opts, -1, 512 * 512);//这里一定要将其设置回false,因为之前我们将其设置成了true     opts.inJustDecodeBounds = false;try {bmp = BitmapFactory.decodeFile(path, opts);} catch (OutOfMemoryError e) {Logger.e(TAG, e.getMessage());}return bmp;}public static Bitmap loadBitmapFromUrl(Context ctx, String url) {File path =  ctx.getCacheDir();String hashedURLString = hashURLString(url);String finalPath = new File(path, hashedURLString).getAbsolutePath();boolean ok = FileUtils.saveUrl(finalPath, url);if (ok) {return loadBitmapFromFile(finalPath);}return null;}    /*** 将图片先放到临时空间中,再读取图片。full load* * @param path* @return*/public static Bitmap loadBitmapFromFileX(String path) {BitmapFactory.Options bfOptions = new BitmapFactory.Options();bfOptions.inDither = false;bfOptions.inPurgeable = true;bfOptions.inTempStorage = new byte[12 * 1024];File file = new File(path);FileInputStream fs = null;Bitmap bmp = null;try {fs = new FileInputStream(file);bmp = BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (OutOfMemoryError e) {e.printStackTrace();} finally {try {if (fs != null) {fs.close();}} catch (IOException e) {e.printStackTrace();}}return bmp;}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;}}private static String hashURLString(String urlString) {try {// Create MD5 HashMessageDigest digest = java.security.MessageDigest.getInstance("MD5");digest.update(urlString.getBytes());byte messageDigest[] = digest.digest();// Create Hex StringStringBuffer hexString = new StringBuffer();for (int i=0; i<messageDigest.length; i++)hexString.append(Integer.toHexString(0xFF & messageDigest[i]));return hexString.toString();} catch (NoSuchAlgorithmException e) {e.printStackTrace();}//fall back to old methodreturn urlString.replaceAll("[^A-Za-z0-9]", "#");}

转载于:https://www.cnblogs.com/Yang2/p/3584948.html

BitmapFactory.Options详解相关推荐

  1. Android中BitmapFactory.Options详解

    在Android中,BitmapFactory相信大家都很熟悉了,这个类里面的所有方法都是用来解码创建一个Bitmap,其中有一个重要的类是Options,此类用于解码Bitmap时的各种参数控制,那 ...

  2. Http:Get、Post、Put、Delete、Head、Options详解

    2019独角兽企业重金招聘Python工程师标准>>> 一.概述 Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE.URL全称是 ...

  3. Cucumber之五Cucumber Options详解

    英文视频教程地址是百度网盘,后续会放到微信公众号:[软测小生]里面,请关注公号更新相关文章和视频资源. ****************************分割线***************** ...

  4. udhcp源码详解(五) 之DHCP包--options字段

    中间有很长一段时间没有更新udhcp源码详解的博客,主要是源码里的函数太多,不知道要不要一个一个讲下去,要知道讲DHCP的实现理论的话一篇博文也就可以大致的讲完,但实现的源码却要关心很多的问题,比如说 ...

  5. Bitmap详解(上)常用概念和常用API

    前言: 图片的操作我相信大家都操作过,在算法层面大家往往都是把图片转成MAT矩阵处理的,而Android 开发层面大多数都是bitmap位图操作.接下来我将分算法层面以及android层面来讲解一下图 ...

  6. 各种图片编码格式详解

    感谢xiangism 常见的图片格式有bmp, jpg(jpeg), png, gif, webp等. 图像基本数据结构 要讲图片格式还先得从图像的基本数据结构说起.在计算机中, 图像是由一个个像素点 ...

  7. Android多点触控详解

    本文转载自GcsSloop的 安卓自定义View进阶-多点触控详解 的文章 Android 多点触控详解,在前面的几篇文章中我们大致了解了 Android 中的事件处理流程和一些简单的处理方案,本次带 ...

  8. android相册和拍照并裁剪图片大小,Android 拍照并对照片进行裁剪和压缩实例详解...

    Android 拍照并对照片进行裁剪和压缩实例详解 本文主要介绍 Android 调用摄像头拍照并对照片进行裁剪和压缩,文中给出了主要步骤和关键代码. 调用摄像头拍照,对拍摄照片进行裁剪,代码如下. ...

  9. (4.6.31)Android Bitmap 详解

    文章目录 一.从相册加载一张图片 1.1 打开相册加载图片 1.2 根据Uri得到Bitmap 二.Bitmap 内存计算方式 2.1 density 和 densityDpi 2.2 getByte ...

最新文章

  1. 1061 Dating
  2. struts2 mysql 乱码_struts2项目插入中文到mysql数据库乱码的解决方法
  3. Linux mmap
  4. leetcood学习笔记-112-路径总和
  5. 学习iptables
  6. mysql inet_aton 与 inet_ntoa 方法
  7. 循序渐进之Spring AOP(5) - 创建切面
  8. EViews10.0程序安装及注意事项
  9. Qt获取本地ip地址
  10. CTF古典密码:移位密码
  11. 矢量网络分析仪(矢网)组成和原理简介
  12. 网络编程之(转载自:https://www.cnblogs.com/clschao/articles/9593164.html)
  13. hadoop培训感想
  14. 2016一路有你,2017一起同行
  15. android的随机之魂
  16. 云计算学习笔记1——并行计算
  17. Elasticsearch的使用RestHighLevelClient
  18. Mac配置mysql环境
  19. 安装Linux Mint 17后要做的20件事
  20. STM32(1)跑马灯

热门文章

  1. echart多个柱状图 设置y轴显示_Echart可视化学习笔记(五)
  2. Cocos Creator教程 ——(二)UI系统介绍(上)
  3. leetcode - 1201. 丑数 III
  4. 时域补零对于DFT谱的影响
  5. C++字符串转化为数字的库函数
  6. php 显示中文utf,php adodb 从mysql数据库中输出中文显示到utf编码网页乱码问题
  7. 事件CEvent的使用
  8. 【入门4】数组 (今天刷洛谷了嘛)
  9. 【编撰】Directfb 深入 002 DirectFB内存分配与管理:surface pool
  10. python死机_请问下为什么我用PYTHON写编译器一旦用READ就死机