BitmapRegionDecoder
尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。
如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常
另外,decodeStream直接拿的图片来读取字节码了, 不会根据机器的各种分辨率来自动适应, 使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源, 否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。
另外,以下方式也大有帮助:
InputStream is = this.getResources().openRawResource(R.drawable.pic1);
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inSampleSize = 10; //width,hight设为原来的十分一
Bitmap btp =BitmapFactory.decodeStream(is,null,options);
注意回收内存
if(!bmp.isRecycle() ){
bmp.recycle() //回收图片所占的内存
system.gc() //提醒系统及时回收
}
最近做的项目里,需要在主页面加载很多图片。那么就尝尝出现OOM,尝试了多种方法,最后找到一种很不错的办法,极大的节省了内存空间,原先程序运行时的内存占有量大约在120-200左右,又时甚至能达到醉人的250直接OOM掉。修改过后,长期稳定在60-100M之间。所以说优化了接近50%。那么现在我们就来看看,我是怎么做的~~
【一】使用Drawable代替bitmap
经过实际测试发现,Drawable在加载图片的性能上和占用内存上都远小于bitmap。(实验证明,加载同样的1000张图片,drawable可以快速的加载完1000张图片,而bitmap仅仅加载到第8张就OOM了。。。)本人才疏学浅不止其中奥义,也不知道为什么大家都爱用bitmap,也希望有识之士能够告知我一下原因。
详见:http://blog.csdn.net/zhu071011/article/details/48310597
【二】使用decodeStream杜绝decodeResource
同样是经过大量实干中得出的经验。decodeStream的加载方式是调用了非java层面的代码进行操作的,所以效率很高。经过试验,用bitmap去加载1000张图片,使用decodeResource的只能加载到第8张,使用decodeStream的可以加载到566张,可见其效率提升的多么显著。
示例:
public static Bitmap readBitMap(Context context, int resId) {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.ARGB_4444;
opt.inPurgeable = true;
opt.inInputShareable = true;
// 获取资源图片
InputStream is = context.getResources().openRawResource(resId);
Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt);
try {
if(is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
【三】巧用BitmapFactroy.Options进行图像高效压缩
网上铺天盖地的都是推荐使用simplesize来进行图像压缩,然而,我却发现一种更节省内存的方法。依然是使用BitmapFactroy.Options,通过设置图片的显示密度来压缩图片,从而达到减小内存占用量的目的。
让我们先看一段示例代码:
public Drawable loadImageFromUrl(int id) {
if(id<0 || id==0) {
return null;
}
int targetdensity = mContext.getResources().getDisplayMetrics().densityDpi;
BitmapFactory.Options opt = new Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inScaled=true;
opt.inTargetDensity=targetdensity;
//inDensity bigger,image memory size smaller.now set to density=screendensityDpi*density
//eg:density = (sw)320*(dpi)2
opt.inDensity = (int)(targetdensity*mContext.getResources().getDisplayMetrics().density);
opt.inJustDecodeBounds = false;
InputStream is = null;
Drawable drawable = null;
try {
is = mContext.getResources().openRawResource(id);
/*Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt);
drawable = new BitmapDrawable(mContext.getResources(), bitmap);*/
drawable = Drawable.createFromResourceStream(mContext.getResources(),null,is,null,opt);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try{
is.close();
} catch (Exception e) {
}
}
}
return drawable;
}