头几天做项目的时候,甲方要求是PAD (SAMSUNG P600 10.1寸 2560*1600)的PAD上显示高分辨率的大图片。
SQLITE采取BOLD方式存储图片,这个存取进程就不说了哈,网上1大堆。
但是在载入/读取/显示图片的时候会报OOM毛病,上网查了很多解决方案还绕了很多弯路,最后还是找到了缘由所在,下面从几个方面来解释1下OOM问题的解决方案。
(谢谢周同学的“尺寸”提示,不然我可能1辈子都要蒙在鼓里)
1.Android APP内存
做1个APP开发的时候,还是不要想着去扩大Android系统赋予的内存上限了,部份老机型老系统16M,大部份都是24M了。
1些大型游戏用dalvik.system.VMRuntime来干涉GC进程(这个类我还没有学过。。。刚听说不久)。
听说用NDK开发时候,C可以动态申请过剩的内存空间,但是我没用过NDK,今后也不打算用了(个人缘由)。
2.图片文件大小
甲方给了1大堆文件大小不1的图片,在载入http://www.wfuyu.com/db/->读取出来->显示出来的这个进程中,出现了很多OOM,分为:
a.载入图片时使用ByteArrayStream创建流,size为Height * Width * 4,OOM;
b.读取图片时候OOM,同上;
c.显示图片时候OOM,decodeResource函数报错,OOM;
开始时候以为是文件大小问题,后来发现有些2M的图片都能显示,但是某些1M的图片确报错,所以在1定范围内,可以证明,图片OOM问题与文件大小无关。
3.图片尺寸(分辨率)
调查这些能显示的图片和不能显示的图片的不同,发现长宽差距很大,那些能成功显示的图片为1005*1500大小,而其他图片都是3000*5000以上。
我用PAINT(1款合适小白的图象处理软件,虽然不如PS但是功能已非常强大了,最新版需要安装NET 4.5)紧缩了图片大小,紧缩到1005*1500,显示成功。
4.函数调用
浏览了这位大神的博客:
http://blog.csdn.net/huangbiao86/article/details/8072128
摘取其中最精华的部份吧:
尽可能不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置1张大图,由于这些函数在完成decode后,终究都是通过java层的createBitmap来完成的,需要消耗更多内存。
因此,改用先通过BitmapFactory.decodeStream方法,创建出1个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。
如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效禁止抛out of Memory异常
另外,decodeStream直接拿的图片来读取字节码了, 不会根据机器的各种分辨率来自动适应, 使用了decodeStream以后,需要在hdpi和mdpi,ldpi中配置相应的图片资源, 否则在不同分辨率机器上都是一样大小(像素点数量),显示出来的大小就不对了。
看来读底层源码还是很有用的,setImageBitmap 和 setImageResource 和 decodeResource在履行进程中还是调用了createBitmap来创建1个新的bitmap,创建bitmap会加重内存消耗,所以不推荐使用了,应当使用decodeStream方法。
图片的紧缩进程也能够设置1个适合的百分比来控制大小。
多张图片的使用中,请注意流的flush与close(我没有及时flush和close的时候也运行正确了,这个有待研究1下,但是为了保证1个良好的习惯还是注意下吧)。
5.关于options方法
网上还有很多文章用BitmapFactory.Options来作为decodeStream时候的1个参数,这个我暂时没有具体实验过,哪位朋友实验过了可以回复交换哈