android加载图片Out Of Memory的解决

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">项目中要加载从网络上获取的图片资源,但是有的图片很大,可以达到1080*1920的尺寸,这么大的图片如果全部载入内存,很容易出现Out Of Memory(OOM)的问题。</span>


解决的方法是利用BitmapFactory.Options。

    HttpURLConnection hp = (HttpURLConnection) imageURL.openConnection();
    InputStream is = hp.getInputStream();
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
     //inJustDecodeBounds设置为true后,decodeStream返回为null,但是options中存储了图片的尺寸信息
				
    BitmapFactory.decodeStream(is, null, options);
    calcuteInSampleSize(options, reqWidth, reqHight);
				
    options.inJustDecodeBounds = false;
    bitmap = BitmapFactory.decodeStream(is, null, options); 

calcuteInSampleSize方法:

	public static int calcuteInSampleSize(BitmapFactory.Options options,
			int reqWidth, int reqHeight) {
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;
		if(height > reqHeight || width > reqWidth) {
			final int heightRadio = Math.round((float) height / (float) reqHeight);
			final int widthRadio = Math.round((float) width / (float) reqWidth);
			
			inSampleSize = heightRadio > widthRadio ? widthRadio : heightRadio;
		}
		return inSampleSize;
	}
返回的inSampleSize可以理解成为一个压缩倍数,比如inSampleSize=2,图片就会以原尺寸的1/2加载入内存。


但是使用的时候会遇到问题,第二次调用decodeStream()时,返回也为 null,log中会出现:

SkImageDecoder::Factory returned null

根据网上资料:链接

 在BitmapFactory.decodeStream中
 // we need mark/reset to work properly
 if (!is.markSupported()) {
 is = new BufferedInputStream(is, DECODE_BUFFER_SIZE);
}
 // so we can call reset() if a given codec gives up after reading up to
 // this many bytes. FIXME: need to find out from the codecs what this
 // value should be.
is.mark(1024);
//...
于是看明白了,第一次取图片尺寸的时候is这个InputStream被使用过了,再真正取图片的时候又使用了这个InputStream,此时流的起始位置已经被移动过了,需要调用is.reset()来重置,然后再decodeStream(imgInputStream, null, options)就没问题了。 但是注意一个问题,is.mark(1024)是SDK中写死的,如果图片的大小超过1024字节,第一次decode取尺寸之后调用is.reset()会抛出IOException,所以建议使用BitmapFactory的其他decode方法,如果是网络读过来的流,最好在本地存成文件缓存,然后通过decodeFileDescriptor方法就没这种问题了。
我还不想去修改业务逻辑,就没使用这种方法。

使用的是另一种解决方法:

    HttpClient httpClient = new DefaultHttpClient();    
    httpClient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
   
    HttpGet httpGet = new HttpGet(imageURI); //注意这里用的是URI,可以用
                                             //imageURI = new URI(imageURL.getProtocol(), imageURL.getHost(), imageURL.getPath(), imageURL.getQuery(), null);将转换一下URL

    HttpResponse response = (HttpResponse).httpClient.execute(httpGet);

    HttpEntity entity = response.getEntity();
    byte [] byteIn = EntityUtils.toByteArray(entity);

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;  //设置为true,返回的bitmap为null
    BitmapFactory.decodeByteArray(byteIn, 0, byteIn.length, options);
    int reqHeight = Global.g_screen_height / 3;
    int reqWidth = reqHeight / 5 * 3;
    options.inJustDecodeBounds=false;
    bitmap = BitmapFactory.decodeByteArray(byteIn, 0, byteIn.length, options);
其实就是使用了decodeByteArray的方法。


同样的,以上解决OOM的方法也可用于decodeFile()加载本地文件使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值