解决Android加载大图片时内存溢出的问题

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;
    }

猜你喜欢

转载自blog.csdn.net/augfun/article/details/88413030
今日推荐