由于在项目需要使用到多图片的处理,因此采取了BitmpFactory的使用,在刚开始的时候,加载多图片,会经常导致内存溢出,也就是常说的OOM,对于OOM,我采取的是压缩图片,先是缩略图后是详细图的做法。在这个过程中,遇到了多个困难,写本篇做一个总结。
对于图片的获取,一般比较常用的都是使用BiamapFactory类,采取这个类下的多个不同方法,通过查看源码可以知道,各个不同的方法最后都是采取流的方式来处理,下面请看具体的源码:
BitmapFactory. decodeResource(Resources,int);
这个方法的具体实现是decodeResource方法,继续查看,
decodeResource的具体实现方法是decodeResourceStream方法,继续查看,
decodeResourceStream的具体实现方法是decodeStream方法,
decodeStream是最终的方法,因此不管前面是哪个方法,只不过在加载图片之前设置了一些对图片处理的参数,因此加载多图的时候,直接使用decodeStream可以减少几个步骤,类似使用方式如下:
InputStream input=Activity.getRescources().openRawResource(resid);
Bitmapbackground=BitmapFactory.decodeStream(input,null,getOpt());
input.close();
后面就是对图片的使用了,这里面使用到的一个参数是Options,下面查看getOpt()方法,(这个方法很简单,只是设置一个参数);
Public static BitmapFactory.OptionsgetOpt(){
BitmapFactory.Optionsopt=new BitmapFactory.Options();
Opt.inSampleSize=4;
Opt.inJustDecodeBounds=false;
Returnopt;
}
源码很简单,但原理还是需要知道的,inSampleSize参数,根据源码的解释可以大概知道它的用法,如果它的值大于1,那么对图片处理的时候,返回的将是比原图小几倍的图片来节省内存,比如,inSampleSize=4,那么返回的图片的宽高将缩小到原图的四分之一,像素点也会减少到原图的十六分之一,依次类推。如果值小于1的话,那么将使用1来代替。这个参数的值推荐使用2的倍数比其他数值可以更快更简单的解码。
以下就是解决多图片出现内存溢出OOM的解决方法之一。
不要以为,到这里就解决了全部问题,那么下面关键的节点来了。
解析图片方式没错,也没有报OOM的异常,可问题就是总有几个图片没出来,查看log可以知道,经常会SkImageDecoder::Factory returnednull的提示出现,经过关键字SkImageDecoder::Factory returned null搜索,出来一大推解决方案,
第一种是:网络获取图片,前面采取HttpClient或者HttpURLConnection方式,最终也是使用BitmapFactory.decodeStream解码图片,说的是网络方式的错误,
可问题是我的是从资源文件res.drawable获取图片,因此这个方法不适合我,
第二种,有人说图片不可以超过1024字节,decodeStream(InputStream,null,Options)这个方法里面有限制,因此建议换其他方式解码图片,根据前面OOM的分析可以知道,不管是哪种方式解码图片,最后都是使用流的方式来解码,也就是说前面不管是什么方法,后面都是经常decodeStream来进入本地方法执行,因此我相信,不存在图片大小的限制。因此这个方法也不适合我。
第三种方法:http://blog.sina.com.cn/s/blog_6400e5c50101qfbx.html
根据文件后缀判断来源是否是图片,其实这里可以看出,解决方法是文件流是图片。
第四种方法:http://blog.csdn.net/kangear/article/details/43928481
这个兄弟好厉害,说的像绕口令一样,我愣是没看明白,不过他的具体方法是怎样,我就不得而知,下面看看我的解决方法。
我的解决方法:
首先,查看数据来源,根据数据来源进行对比,
注意箭头所指的方向,前面部分是decodeStream返回为空的id,后面是名称和id的对应表,根据对应表,一下就可以发现,返回为空都不是图片。
All,all_normal类的都是我自定义的xml不是图片,从此思路一片光明。
最后说明,SkImageDecoder::Factory returned null,终极解决方法,确保数据来是真正的图片。
3.总结:
1、 BitmapFactory的几个解码方式,最终都是以下decodeStream为入口进入本地方法;
2、 不管是网络操作还是本地操作,只要确保数据来源是图片就不会返回这个异常;
3、 Android本身并没有对图片做一个1024字节的限制,至于最大的限制是多大,那就是要看堆内存中能容纳多大的对象。