最近因为项目里需求是选择或者拍摄多张照片后,提供滑动预览和上传,很多照片是好几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,因为之前我们将其设置成了trueopts.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>(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<String, SoftReference<Bitmap>> imageCache;    private Context context;        public AsyncImageLoaderByPath(Context context) {        this.imageCache = new HashMap<String, SoftReference<Bitmap>>();        this.context = context;    }    public Bitmap loadBitmapByPath(final String imagePath, final ImageView imageView, final ImageCallback imageCallback){        if (imageCache.containsKey(imagePath)) {            //从缓存中获取            SoftReference<Bitmap> 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>(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张照片进行滑动预览:






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


更多相关文章

  1. Android使用WebView浏览有声音或者视频的网页,关闭WebView之后,声
  2. android图片特效处理之光晕效果
  3. android开发 加载so库的解析和出现的各种错误分析
  4. Android中高效的显示图片之三——缓存图片
  5. [置顶] Android获取本地图片缩略图终极解决方案
  6. android 一行代码,快速实现图片验证码(附android studio 版小demo)
  7. android 设置头像以及裁剪功能
  8. 你需要知道的Android拍照适配方案
  9. Android中的图片处理——色彩、形状拉伸变化(Matrix,ColorMatrix)

随机推荐

  1. SnackBar学习记录
  2. RN填坑之旅
  3. rust on android
  4. Android中textview字体动画
  5. React-native 问题汇总
  6. Android(安卓)下拉控件:Spinner
  7. Android(安卓)近场通信(NFC)
  8. adb for remote connections
  9. android contentProvider 小例子
  10. Android(安卓)resource notlong / long i