http://stormzhang.github.io/android/2013/11/20/android-display-bitmaps-efficiently/ android
Android加载资源图片时,很容易出现OOM的错误。
git
由于Android系统对内存有一个限制,若是超出该限制,就会出现OOM。为了不这个问题,须要在加载资源时尽可能考虑如何节约内存,尽快释放资源等等。github
Android系统版本对图片加载,回收的影响:数组
1,在Android 2.3以及以后,采用的是并发回收机制,避免在回收内存时的卡顿现象。缓存
2,在Android 2.3.3(API Level 10)以及以前,Bitmap的backing pixel 数据存储在native memory, 与Bitmap自己是分开的,Bitmap自己存储在dalvik heap 中。致使其pixel数据不能判断是否还须要使用,不能及时释放,容易引发OOM错误。 从Android 3.0(API 11)开始,pixel数据与Bitmap一块儿存储在Dalvik heap中。并发
在加载图片资源时,可采用如下一些方法来避免OOM的问题:spa
1,在Android 2.3.3以及以前,建议使用Bitmap.recycle()方法,及时释放资源。code
2,在Android 3.0开始,可设置BitmapFactory.options.inBitmap值,(从缓存中获取)达到重用Bitmap的目的。若是设置,则inPreferredConfig属性值会被重用的Bitmap该属性值覆盖。orm
3,经过设置Options.inPreferredConfig值来下降内存消耗:图片
默认为ARGB_8888: 每一个像素4字节. 共32位。
Alpha_8: 只保存透明度,共8位,1字节。
ARGB_4444: 共16位,2字节。
RGB_565:共16位,2字节。
若是不须要透明度,可把默认值ARGB_8888改成RGB_565,节约一半内存。
4,经过设置Options.inSampleSize 对大图片进行压缩,可先设置Options.inJustDecodeBounds,获取Bitmap的外围数据,宽和高等。而后计算压缩比例,进行压缩。
5,设置Options.inPurgeable和inInputShareable:让系统能及时回收内存。
inPurgeable:设置为True,则使用BitmapFactory建立的Bitmap用于存储Pixel的内存空间,在系统内存不足时能够被回收,当应用须要再次访问该Bitmap的Pixel时,系统会再次调用BitmapFactory 的decode方法从新生成Bitmap的Pixel数组。
设置为False时,表示不能被回收。
inInputShareable:设置是否深拷贝,与inPurgeable结合使用,inPurgeable为false时,该参数无心义。
True: share a reference to the input data(inputStream, array,etc) 。 False :a deep copy。
6,使用decodeStream代替其余decodeResource,setImageResource,setImageBitmap等方法来加载图片。
区别:
decodeStream直接读取图片字节码,调用nativeDecodeAsset/nativeDecodeStream来完成decode。无需使用Java空间的一些额外处理过程,节省dalvik内存。可是因为直接读取字节码,没有处理过程,所以不会根据机器的各类分辨率来自动适应,须要在hdpi,mdpi和ldpi中分别配置相应的图片资源,不然在不一样分辨率机器上都是一样的大小(像素点数量),显示的实际大小不对。
decodeResource会在读取完图片数据后,根据机器的分辨率,进行图片的适配处理,致使增大了不少dalvik内存消耗。
decodeStream调用过程:
decodeStream(InputStream,Rect,Options) -> nativeDecodeAsset/nativeDecodeStream
decodeResource调用过程:即finishDecode以后,调用额外的Java层的createBitmap方法,消耗更多dalvik内存。
decodeResource(Resource,resId,Options) -> decodeResourceStream (设置Options的inDensity和inTargetDensity参数) -> decodeStream() (在完成Decode后,进行finishDecode操做)
finishDecode() -> Bitmap.createScaleBitmap()(根据inDensity和inTargetDensity计算scale) -> Bitmap.createBitmap()
以上方法的组合使用,合理避免OOM错误。