Android 图片压缩策略详解,有效解决 Android 程序 OOM( 二 )


  1. 既能获得图片大小,由于后续操作
  2. 又成功避免了去解析图片,导致程序 OOM 而崩溃 。
但这恰恰是被很多人所忽略的一点 。
好了,现在给出具体的实现:
Android 图片压缩策略详解,有效解决 Android 程序 OOM

文章插图
 
大家可能发现,这里只将 inJustDecodeBounds 设为true却没有改回false,这是因为获得 Options 只是图片压缩的第一步,我们在后续方法中将会进行修改

Android 图片压缩策略详解,有效解决 Android 程序 OOM

文章插图
 
四、如何进行压缩我们继续看 Options 的构成 。我们发现,其中有个名为 inSampleSize 的数据成员,他就是关键所在,那么他有着什么意义呢?
这里我给大家举个例子,比如我这有张 4000*1000 像素的图片:
  • 当我们把 inSampleSize 的值设为 4时,最后生成出来的图片大小将会是:1000 x 250 像素
  • 当我们把inSampleSize 的值设为5时,最后生成出来的图片大小将会是:800 x 200 像素 。这是个什么概念?
这不仅仅是长宽都变为原来四分之一或者五分之一这么简单,而是其图片大小,直接变为原图的 1/(n^2)!也就是说:
  • 如果原图 2MB,那么当 inSampleSize 赋值为4加载时就只需要 0.125MB
  • 那 如果 inSampleSize 赋值为 5 呢?只需要 0.08 MB!连100k 都不到的小图啊!
那么下面我就给出这个方法的具体实现:
Android 图片压缩策略详解,有效解决 Android 程序 OOM

文章插图
 
我们发现,这里我先计算出了,原图尺寸与目标大小大比例,在三目运算符中,将inSamplesize 赋值为较大的一个 。为什么不用小的那一个呢?这里我就卖个关子,大家可以在评论区中发表自己的想法
五、生成目标图片经过前面的两个步骤,想必大家已经能勾勒处这最后一步的做法了,思路非常简单:
  1. 先生成一个 Options对象
  2. 将 Options 的 inJustDecodeBounds设置为true
  3. 接着调用方法一calculateOptionsById获得原图尺寸到Options中
  4. 调用方法三calculateInSamplesizeByOptions 获得相应的inSampleSize 对象
  5. 将 Options的inJustDecodeBounds改回 false
  6. 再次调用 decode...()方法(这里是 decodeResource )获得压缩后的 Bitmap对象
具体实现如下
Android 图片压缩策略详解,有效解决 Android 程序 OOM

文章插图
 
非常棒,我们赶紧看看效果:
Android 图片压缩策略详解,有效解决 Android 程序 OOM

文章插图
 
太棒了,几乎和原图效果一摸一样,但软件运行的流畅性确大大提高了!但是,这真的就完美了吗?
最求完美的我们可能会有个想法:如果调用我们方法的人,或者说特殊时候的我们 。不想用这个已经写好的 decodeBitmapById方法,而是像自己通过前两个方法:calculateOptionsById calculateInSamplesizeByOptions 来实现图片压缩功能,这是问题就出现了:
  • 调用 calculateOptionsById 前可能忘记,设置 inJustDecodeBound 为 true,进而导致计算超大图时,直接发生 OOM
  • 调用完 calculateInSamplesizeByOptions 后可能忘记,设置inJustDecodeBounds 为 false,进而导致无法获得Bitmap 对象,一脸懵逼
  • 啥都做了结果调用完 calculateInSamplesizeByOptions 没把没回的值赋给 options.inSampleSize,白忙活一场
所以,我们需要在优化一下:
首先,在calculateOptionsById中,默认将 options.inJustDecodeBounds 设置为true:
Android 图片压缩策略详解,有效解决 Android 程序 OOM

文章插图
 
其次,在 calculateInSamplesizeByOptions最后,默认将 options.inJustDecodeBounds设置为false:
Android 图片压缩策略详解,有效解决 Android 程序 OOM

文章插图
 
为什么不在该方法后面,对 options.inSampleSize进行赋值呢?这主要是防止,有时我们可能只想得到计算相应比例来做其他操作,而不想改变原有属性,所以是否赋值,就交给用户去选择吧
总结好了,到这里为止,历时有关图片压缩的所有坑坑洼洼都已经总结好了,我们从头理以边思路:
  1. 借助options.inJustDecodeBounds 参数赋值true时,不生成图片的特性,将原图尺寸保存在 Options 中
  2. 通过 options 中原图尺寸与目标(控件)尺寸的比例,对 options.inSampleSize 进行设置
  3. 生成目标图片
  4. 压缩的问题解决了,但是每次打开图片都压缩也太麻烦了!下面我将针对这个问题进行更有效地解决,有兴趣可以继续关注 _yuanhao 的编程世界


    推荐阅读