如何压缩图片避免Android程序OOM?终极奥义是?

摘要:由来 在我们编写 程序的时候,几乎永远逃避不了图片压缩的难题。除了应用图标之外,我们所要显示的图片基本上只有两个来源: 来自网络下载 本地相册中加载 不管是网上下载下来的也好,还是从系统图片库中读取的图片,都有一个相同的特点:像素一帮较高。
由来 在我们编写 Android 程序的时候,几乎永远逃避不了图片压缩的难题。除了应用图标之外,我们所要显示的图片基本上只有两个来源: 来自网络下载 本地相册中加载 不管是网上下载下来的也好,还是从系统图片库中读取的图片,都有一个相同的特点:像素一帮较高。同时我们都知道,Android 系统分配给我们每个应用的内存是有限的,由于解析、加载一张图片,需要占用的内存大小,是远大于图片自身大小的。所以,这时程序就可能因为占用了过多的内存,从而出现 OOM 现象。那么什么是 OOM 呢? Exception java.lang.OutOfMemoryError: Failed to allocate a 916 byte allocation with 8388608 free bytes and 369MB until OOM; failed due to fragmentation (required continguous free 65536 bytes for a new buffer where largest contiguous free 32768 bytes) java.nio.CharBuffer.allocate (CharBuffer.java:54) java.nio.charset.CharsetDecoder.allocateMore (CharsetDecoder.java:226) java.nio.charset.CharsetDecoder.decode (CharsetDecoder.java:188) org.java_websocket.util.Charsetfunctions.stringUtf8 (Charsetfunctions.java:77) org.java_websocket.WebSocketImpl.decodeFrames (WebSocketImpl.java:375) org.java_websocket.WebSocketImpl.decode (WebSocketImpl.java:158) org.java_websocket.client.WebSocketClient.run (WebSocketClient.java:185) java.lang.Thread.run (Thread.java:818) OOM 即 OutOfMemory 异常,也就是我们所说的 内存溢出 ,其一般表现为应用闪退等现象。那么我们该如何下手去解决呢? 解决方案 首先我们发现,我们所加载的这些图片的分辨率,要比我们手机屏幕高得多,更有甚者,我们在一个拇指大的控件上,去加载一个 4k 大图是完全没有必要的,也就是说,如果我们能让每个控件上都去显示相应大小的图片,那么这个问题也就迎刃而解了 那么,要怎样才能达到图片与控件的对号入座?这时我们就引进了图片压缩的方案: 首先,获得原图片大小 其次,获取控件大小 接着,获取我们图片和控件的比例 最后,根据这一比例,将图片压缩为适合显示的大小 那么就让我们开始吧: 获取原图大小 我们都知道,Android 向我们提供了 BitmapFactory 这个类,在这个类中有着诸如:decodeResource() decodeFile() decodeStream() 等: public static Bitmap decodeResource(Resources res, int id) public static Bitmap decodeFile(String pathName) public static Bitmap decodeStream(InputStream is) 其中: decodeResource() : 用于解析资源文件,即 res 文件夹下的图片 decodeFile() : 用于解析系统相册中的图片 decodeStream() : 用于解析输入输出流中图片通常,是采用 HttpClient 从下载的图片 其他的方法这里就不多说了,因为在源码中我们可有i看到,几乎所有的方法,最后都会将图片解析为流的形式,最后调用 decodeStream() 方法,实例化出我们的 Bitmap 对象。 虽然这些方法对我们是再熟悉不过的了,但对于某些初学者而言,却经常忽略了一个重要的内部类 :BitmapFactory.Options ,然而他确实我们图片压缩必不可少的,为什么需要这个参数呢?Options 的对象用于确定需要生成的 Bitmap 即目标图片的参数。 他的用法很简单,我们先 new 一个 BitmapFactory.Options 对象。
阅读全文