如何避免图片加载OOM

在编写程序的时候,经常需要显示很多图片,当图片质量较高,尺寸和分辨率较大时,我们的程序可能吃不消!因为程序都有一定的内存大小限制,这就可能会造成OOM(内存溢出)。

那么,该如何解决这个问题呢?思路就是,在展示高分辨率的图片的时候,肯定会对其进行压缩,然后根据控件的大小调整。 

最基本的压缩方法:BitmapFactory

BitmapFactory提供了一个Options的方法,该方法里面包含了解析图片的相关参数,当我们第一次解析图片的时候因为不确定图片的大小,所以建议设置Options.InjustdecodeBounds=true,这样的话BitmapFactory.decodeResources(res,id,options)只会去解析图片的宽高和MiME类型,并不会为其分配内存,其中options.outwidth和option.height可以的到图片的宽高,知道宽高以后我们就可以对其进行缩放了,options.simpleSize这个属性可以按比例压缩图片,当然这个simpleSize需要经过计算,最后设置injustdecodebounds=false,就可以返回bitmap了

 /**
     * @param res   getResources
     * @param resID R.id.image
     * @param w     期望的宽
     * @param h     期望的高
     */
    public static Bitmap decodeImage(Resources res, int resID, int w, int h) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        //第一次解析图片,不分配内存,只得到宽和高
        BitmapFactory.decodeResource(res, resID, options);
        options.inSampleSize = calaculateSampleSize(options, w, h);
        options.inJustDecodeBounds=false;
        //根据得到的宽高再次解析图片
        return BitmapFactory.decodeResource(res,resID,options);

    }

    static int calaculateSampleSize(BitmapFactory.Options options, int w, int h) {
        //图片原本的宽和高
        int width = options.outWidth;
        int height = options.outHeight;
        int simpleSize = 1;
        if (width > w || height > h) {
            int widthRadio = Math.round((float) width / (float) w);
            int heightRadio = Math.round((float) height / (float) h);
            // 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高
            // 一定都会大于等于目标的宽和高。
            simpleSize=widthRadio>heightRadio?heightRadio:widthRadio;
        }
        return simpleSize;
    }

OK,这只是加载一张图片,那么问题来了,如果成百上千张图片怎么办呢?程序中我们经常使用listview,girdview,recycleView等联网加载大量图片,在不断滑动的时候会不断的去解析加载图片,结果可想而知,图片不断增加,最终导致OOM,有人会说,我把屏幕之外的图片进行释放,只显示屏幕当中的图片不就行了?听起来好像没错,的确可以减轻程序的内存压力,但是另外一个问题又出现了,我们不断的回收图片,那么重新加载的时候岂不是又消耗了内存、流量和时间?这里不得不提出一个新的概念:缓存

在androidV4包中提供了一个类:LruCache,这个类提供了一套算法,可以把最近使用的对象强引用存储在LinkedHashMap ,把最近最少使用的对象在缓存达到峰值时从内存中删除,那么如何使用呢?

private LruCache<String, Bitmap> mMemoryCache;

@Override
protected void onCreate(Bundle savedInstanceState) {
	// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
	// LruCache通过构造函数传入缓存值,以KB为单位。
	int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
	// 使用最大可用内存值的1/8作为缓存的大小。
	int cacheSize = maxMemory / 8;
	mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
		@Override
		protected int sizeOf(String key, Bitmap bitmap) {
			// 重写此方法来衡量每张图片的大小,默认返回图片数量。
			return bitmap.getByteCount() / 1024;
		}
	};
}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
	if (getBitmapFromMemCache(key) == null) {
		mMemoryCache.put(key, bitmap);
	}
}

public Bitmap getBitmapFromMemCache(String key) {
	return mMemoryCache.get(key);
}
public void loadBitmap(int resId, ImageView imageView) {
	final String imageKey = String.valueOf(resId);
	final Bitmap bitmap = getBitmapFromMemCache(imageKey);
	if (bitmap != null) {
		imageView.setImageBitmap(bitmap);
	} else {
		imageView.setImageResource(R.drawable.image_placeholder);
		BitmapWorkerTask task = new BitmapWorkerTask(imageView);
		task.execute(resId);
	}
}
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
	// 在后台加载图片。
	@Override
	protected Bitmap doInBackground(Integer... params) {
		final Bitmap bitmap =decodeImage(getResources(), params[0], 100, 100);

addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);return bitmap;}}

以上内容参考bolg:http://blog.csdn.net/guolin_blog/article/details/9316683



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值