博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
彻底解决Android因加载多个大图引起的OutOfMemoryError,内存溢出的问题
阅读量:5124 次
发布时间:2019-06-13

本文共 5298 字,大约阅读时间需要 17 分钟。

最近因为项目里需求是选择或者拍摄多张照片后,提供滑动预览和上传,很多照片是好几MB一张,因为目前的Android系统对运行的程序都有一定的内存限制,一般是16MB或24MB(视平台而定),不做处理直接加载的话必然会报OOM (Out Of Memmory)。网上有很多解决android加载bitmap内存溢出的方法,我总结了一个通用的方法,下面是我从的开发案例抽取出来的代码:

我在项目中建了个Util.java工具类,里面写了个方法,根据图片的路径返回一个字节流数组对象:

 

public static byte[] decodeBitmap(String path) {		BitmapFactory.Options opts = new BitmapFactory.Options();		opts.inJustDecodeBounds = true;// 设置成了true,不占用内存,只获取bitmap宽高		BitmapFactory.decodeFile(path, opts);		opts.inSampleSize = computeSampleSize(opts, -1, 1024 * 800);		opts.inJustDecodeBounds = false;// 这里一定要将其设置回false,因为之前我们将其设置成了true		opts.inPurgeable = true;		opts.inInputShareable = true;		opts.inDither = false;		opts.inPurgeable = true;		opts.inTempStorage = new byte[16 * 1024];		FileInputStream is = null;		Bitmap bmp = null;		ByteArrayOutputStream baos = null;		try {			is = new FileInputStream(path);			bmp = BitmapFactory.decodeFileDescriptor(is.getFD(), null, opts);			double scale = getScaling(opts.outWidth * opts.outHeight,					1024 * 600);			Bitmap bmp2 = Bitmap.createScaledBitmap(bmp,					(int) (opts.outWidth * scale),					(int) (opts.outHeight * scale), true);			bmp.recycle();			baos = new ByteArrayOutputStream();			bmp2.compress(Bitmap.CompressFormat.JPEG, 100, baos);			bmp2.recycle();			return baos.toByteArray();		} catch (FileNotFoundException e) {			e.printStackTrace();		} catch (IOException e) {			e.printStackTrace();		} finally {			try {				is.close();				baos.close();			} catch (IOException e) {				e.printStackTrace();			}			System.gc();		}		return baos.toByteArray();	}	private static double getScaling(int src, int des) {		/**		 * 48 目标尺寸÷原尺寸 sqrt开方,得出宽高百分比 49		 */		double scale = Math.sqrt((double) des / (double) src);		return scale;	}	public static int computeSampleSize(BitmapFactory.Options options,			int minSideLength, int maxNumOfPixels) {		int initialSize = computeInitialSampleSize(options, minSideLength,				maxNumOfPixels);		int roundedSize;		if (initialSize <= 8) {			roundedSize = 1;			while (roundedSize < initialSize) {				roundedSize <<= 1;			}		} else {			roundedSize = (initialSize + 7) / 8 * 8;		}		return roundedSize;	}	private static int computeInitialSampleSize(BitmapFactory.Options options,			int minSideLength, int maxNumOfPixels) {		double w = options.outWidth;		double h = options.outHeight;		int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math				.sqrt(w * h / maxNumOfPixels));		int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(				Math.floor(w / minSideLength), Math.floor(h / minSideLength));		if (upperBound < lowerBound) {			return lowerBound;		}		if ((maxNumOfPixels == -1) && (minSideLength == -1)) {			return 1;		} else if (minSideLength == -1) {			return lowerBound;		} else {			return upperBound;		}	}

 

然后在我需要加载图片BitMap的地方来调用Util.decodeBitmap():

 

Bitmap bitmap = BitmapFactory.decodeByteArray(Util.decodeBitmap(imagePath), 0, Util.decodeBitmap(imagePath).length);                imageCache.put(imagePath, new SoftReference
(bitmap));

 

上面这两行是我的AsyncImageLoaderByPath类中的代码,用来加载SD卡里面的图片,该类完整代码是:

 

package com.pioneer.travel.util;import java.io.IOException;import java.io.InputStream;import java.lang.ref.SoftReference;import java.net.MalformedURLException;import java.net.URL;import java.util.HashMap;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.BitmapFactory.Options;import android.graphics.drawable.Drawable;import android.os.Handler;import android.os.Message;import android.provider.MediaStore;import android.util.Log;import android.widget.ImageView;public class AsyncImageLoaderByPath {    //SoftReference是软引用,是为了更好的为了系统回收变量    private HashMap
> imageCache; private Context context; public AsyncImageLoaderByPath(Context context) { this.imageCache = new HashMap
>(); this.context = context; } public Bitmap loadBitmapByPath(final String imagePath, final ImageView imageView, final ImageCallback imageCallback){ if (imageCache.containsKey(imagePath)) { //从缓存中获取 SoftReference
softReference = imageCache.get(imagePath); Bitmap bitmap = softReference.get(); if (bitmap != null) { return bitmap; } } final Handler handler = new Handler() { public void handleMessage(Message message) { imageCallback.imageLoaded((Bitmap) message.obj, imageView, imagePath); } }; //建立新一个获取SD卡的图片 new Thread() { @Override public void run() { Bitmap bitmap = BitmapFactory.decodeByteArray(Util.decodeBitmap(imagePath), 0, Util.decodeBitmap(imagePath).length); imageCache.put(imagePath, new SoftReference
(bitmap)); Message message = handler.obtainMessage(0, bitmap); handler.sendMessage(message); } }.start(); return null; } //回调接口 public interface ImageCallback { public void imageLoaded(Bitmap imageBitmap,ImageView imageView, String imagePath); }}

 

通过这个实例,我验证了一下,一次性获取20张5MB的照片,都可以加载的很流畅,完全没有再出现报OOM的错误了

以下是运行效果

SD卡中的图片:

进入应用,选择11张照片进行滑动预览:

希望以上所写对大家有帮助,谢谢!

 

转载于:https://www.cnblogs.com/suncoolcat/p/3315403.html

你可能感兴趣的文章
团队开发之个人博客八(4月27)
查看>>
发布功能完成
查看>>
【原】小程序常见问题整理
查看>>
C# ITextSharp pdf 自动打印
查看>>
【Java】synchronized与lock的区别
查看>>
django高级应用(分页功能)
查看>>
【转】Linux之printf命令
查看>>
关于PHP会话:session和cookie
查看>>
STM32F10x_RTC秒中断
查看>>
display:none和visiblity:hidden区别
查看>>
C#double转化成字符串 保留小数位数, 不以科学计数法的形式出现。
查看>>
牛的障碍Cow Steeplechase
查看>>
Zookeeper选举算法原理
查看>>
3月29日AM
查看>>
利用IP地址查询接口来查询IP归属地
查看>>
HTML元素定义 ID,Class,Style的优先级
查看>>
构造者模式
查看>>
http和https的区别
查看>>
Hbuild在线云ios打包失败,提示BuildConfigure Failed 31013 App Store 图标 未找到 解决方法...
查看>>
找到树中指定id的所有父节点
查看>>