android端读取本地图片出现OutOfMemoryException解决办法

前些日子一直为图片内存溢出问题困扰着,查了N多资料,将google彻底翻遍了都没找到解决方案,就当我几乎绝望的时候意外发现了一位网友的一个工具类,抱着最后一丝希望将代码co过来试了一把,结果令我喜出望外。嘿,解决了!暂不说多么欢喜了,听我慢慢道来这其中的前因后果吧!

需求:下载时候将图片一并down下来,在空间里显示并支持离线观看

第一个版本代码:

   //从本地读取图片
    public Bitmap getBitmapFromSD(String filename) {
        FileInputStream fi = null;
        BufferedInputStream bi = null;
        Bitmap bp = null;
        try {
            fi = new FileInputStream(filename);
            bi = new BufferedInputStream(fi);
            bp = BitmapFactory.decodeStream(bi);
        } catch (IOException e) {
            bp = null;
        } finally {
            try {
                if (bi != null) {
                    bi.close();
                }
                if (fi != null) {
                    fi.close();
                }
            } catch (IOException e) {
                bp = null;
            }
        }
        return bp;
    }

问题出现了,由于显示的图片过大,所以会出现OutOfMemoryException。我就设想能否捕捉异常来回收图片再重新加载,于是欲从网上找解决办法,什么手动干预GC,什么将图片弱化什么使用弱引用保存图片,有些总结得特别好(http://mzh3344258.blog.51cto.com/1823534/804237),这些方法我一一尝试可问题仍然未解决。不断的OOM,不断的尝试recycle,错误倒是不出现,可一旦内存吃不消就会显示不了图片,出现的都是默认图片。最终我从网上找到如下工具类,助我很好的解决了此问题,具体网址忘记了(得谢谢那位网友啦(*^__^*)),现在代码贴出来以便下次顺手拈来

public final class BitMapUtil {
      private static final Size ZERO_SIZE = new Size(0, 0);
      private static final Options OPTIONS_GET_SIZE = new Options();
      private static final Options OPTIONS_DECODE = new Options();
      private static final byte[] LOCKED = new byte[0];
// 此对象用来保持Bitmap的回收顺序,保证最后使用的图片被回收
      private static final LinkedList CACHE_ENTRIES = new LinkedList();
// 线程请求创建图片的队列
     private static final Queue TASK_QUEUE = new LinkedList();
// 保存队列中正在处理的图片的key,有效防止重复添加到请求创建队列
     private static final Set TASK_QUEUE_INDEX = new HashSet();
// 缓存Bitmap
     private static final Map IMG_CACHE_INDEX = new HashMap();                         // 通过图片路径,图片大小
     private static int CACHE_SIZE = 20; // 缓存图片数量
   static {
     OPTIONS_GET_SIZE.inJustDecodeBounds = true;
  // 初始化创建图片线程,并等待处理
  new Thread() {
   {
    setDaemon(true);
   }
   public void run() {
    while (true) {
     synchronized (TASK_QUEUE) {
      if (TASK_QUEUE.isEmpty()) {
       try {
        TASK_QUEUE.wait();
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
      }
     }
     QueueEntry entry = TASK_QUEUE.poll();
     String key = createKey(entry.path, entry.width,
       entry.height);
     TASK_QUEUE_INDEX.remove(key);
     createBitmap(entry.path, entry.width, entry.height);
    }
   }
  }.start();
 }

 public static Bitmap getBitmap(String path, int width, int height) {
        if(path==null){
            return null;
        }
  Bitmap bitMap = null;
  try {
   if (CACHE_ENTRIES.size() >= CACHE_SIZE) {
    destoryLast();
   }
   bitMap = useBitmap(path, width, height);
   if (bitMap != null && !bitMap.isRecycled()) {
    return bitMap;
   }
   bitMap = createBitmap(path, width, height);
   String key = createKey(path, width, height);
   synchronized (LOCKED) {
    IMG_CACHE_INDEX.put(key, bitMap);
    CACHE_ENTRIES.addFirst(key);
   }
  } catch (OutOfMemoryError err) {
   destoryLast();
   System.out.println(CACHE_SIZE);
   return createBitmap(path, width, height);
  }
  return bitMap;
 }

 public static Size getBitMapSize(String path) {
  File file = new File(path);
  if (file.exists()) {
   InputStream in = null;
   try {
    in = new FileInputStream(file);
    BitmapFactory.decodeStream(in, null, OPTIONS_GET_SIZE);
    return new Size(OPTIONS_GET_SIZE.outWidth,
      OPTIONS_GET_SIZE.outHeight);
   } catch (FileNotFoundException e) {
    return ZERO_SIZE;
   } finally {
    closeInputStream(in);
   }
  }
  return ZERO_SIZE;
 }

 // ------------------------------------------------------------------ private Methods
 // 将图片加入队列头
 private static Bitmap useBitmap(String path, int width, int height) {
  Bitmap bitMap = null;
  String key = createKey(path, width, height);
  synchronized (LOCKED) {
   bitMap = IMG_CACHE_INDEX.get(key);
   if (null != bitMap) {
    if (CACHE_ENTRIES.remove(key)) {
     CACHE_ENTRIES.addFirst(key);
    }
   }
  }
  return bitMap;
 }

 // 回收最后一张图片
 private static void destoryLast() {
  synchronized (LOCKED) {
   String key = CACHE_ENTRIES.removeLast();
   if (key.length() > 0) {
    Bitmap bitMap = IMG_CACHE_INDEX.remove(key);
    if (bitMap != null && !bitMap.isRecycled()) {
     bitMap.recycle();
     bitMap = null;
    }
   }
  }
 }

 // 创建键
 private static String createKey(String path, int width, int height) {
  if (null == path || path.length() == 0) {
   return "";
  }
  return path + "_" + width + "_" + height;
 }

 // 通过图片路径,宽度高度创建一个Bitmap对象
 private static Bitmap createBitmap(String path, int width, int height) {
  File file = new File(path);
  if (file.exists()) {
   InputStream in = null;
   try {
    in = new FileInputStream(file);
    Size size = getBitMapSize(path);
    if (size.equals(ZERO_SIZE)) {
     return null;
    }
    int scale = 1;
    int a = size.getWidth() / width;
    int b = size.getHeight() / height;
    scale = Math.max(a, b);
    synchronized (OPTIONS_DECODE) {
     OPTIONS_DECODE.inSampleSize = scale;
     Bitmap bitMap = BitmapFactory.decodeStream(in, null,
       OPTIONS_DECODE);
     return bitMap;
    }
   } catch (FileNotFoundException e) {
                Log.v("BitMapUtil","createBitmap=="+e.toString());
   } finally {
    closeInputStream(in);
   }
  }
  return null;
 }

 // 关闭输入流
 private static void closeInputStream(InputStream in) {
  if (null != in) {
   try {
    in.close();
   } catch (IOException e) {
    Log.v("BitMapUtil","closeInputStream=="+e.toString());
   }
  }
 }

 // 图片大小
 static class Size {
  private int width, height;
  Size(int width, int height) {
   this.width = width;
   this.height = height;
  }
  public int getWidth() {
   return width;
  }
  public int getHeight() {
   return height;
  }
 }

 // 队列缓存参数对象
 static class QueueEntry {
  public String path;
  public int width;
  public int height;
 }
}
 

在使用时我只调用了getBitmap方法,将需要设置的高度宽度以及本地图片路径传递过去就能自动返回bitmap给我,而且当捕捉到OOMError的时候将LinkedList的最后一张图片也就是最先存的图片进行溢出并回收就大功告成,特别注意的是这里捕捉错误Exception是获取不到的,一定要手动捕获OutOfMemoryError你才能进行处理(估计这些道理大家都懂得,所以不赘述啦,童鞋们加油!办法总比困难多o(∩_∩)o

时间: 2024-10-13 03:04:32

android端读取本地图片出现OutOfMemoryException解决办法的相关文章

[转]android端读取本地图片出现OutOfMemoryException

前些日子一直为图片内存溢出问题困扰着,查了N多资料,将google彻底翻遍了都没找到解决方案,就当我几乎绝望的时候意外发现了一位网友的一个工具类,抱着最后一丝希望将代码co过来试了一把,结果令我喜出望外.嘿,解决了!暂不说多么欢喜了,听我慢慢道来这其中的前因后果吧! 需求:下载时候将图片一并down下来,在空间里显示并支持离线观看 第一个版本代码: //从本地读取图片    public Bitmap getBitmapFromSD(String filename) {        FileI

android.os.BadParcelableException: ClassNotFoundException when unmarshalling:解决办法

例如在用AlarmManager的时候 1 AlarmManager alarmMgr = (AlarmManager) mContext 2 .getSystemService(Context.ALARM_SERVICE); 3 Intent intent = new Intent(ALARM_ALERT); 4 // intent.setExtrasClassLoader(DBTask.class.getClassLoader()); 5 Bundle mBundle=new Bundle(

android sqlite3程序不存在的解决办法(转)

在android开发中,在使用命令行操作数据库sqlite时,有时候会遇到sqlite3 not found的问题.这是因为你的手机没有安装sqlite3程序.解决办法如下(两种办法结合起来解释的更清楚!!!): 方法1: sqlite3 not found的解决办法(转) 在Android开发方面,我是小白,起步没多久.最近用到了sqlite本地缓存数据,我希望像mysql一样通过命令行查看建立的表以及表中的数据,于是用adb shell进入,敲入sqlite3,提示 sqlite3: not

配置Android环境遇到的问题及解决办法

配置Android环境遇到的问题及解决办法: 1 环境安装地址 http://pan.baidu.com/s/1jGzNzyI 2 其他: 2.1 安装 2.1.1 安装JDK,JRE 成功安装之后,进行测试是否真的成功安装,点击[开始]----[运行]----输入 CMD,在命令提示符里面输入"Java -version"并按回车键,出现版本号则安装成功. 2.1.2 安装Adb 2.1.3 打开Eclipse 2.2 配置环境变量: 2.2.1 配置JAVA环境变量 (见下方2.2

pureftp 读取目录列表失败解决办法

最近在使用pureftp的时候遇到了文件目录无法读取或者读取很慢的问题,同时服务器上配置了iptables防火墙规则,问题主要由此引起. 解决方法如下: 1.首先查看是否开启了20.21端口,如果没有请开启. 2.停止iptables:service iptables stop,再次连接,可以成功读取列表. 3.修改iptables-config配置文件: 打开:vim /etc/sysconfig/iptables-config 将IPTABLES_MODULES修改为:IPTABLES_MO

Eclipse下ADB报错:Android ADB server didn't ACK,解决办法

转载请注明出处:http://blog.csdn.net/xiaanming/article/details/9401981 ADB server didn't ACK 这个问题会困恼很多的新手朋友,我以前刚开始做Android的时候也遇到过这个问题,不过自己百度,google啥的,也不知道怎么就给解决了,看到群里很多新手朋友都会问这个问题,说实话我也没有一个解决这个问题的终极方法(百试百灵的那种,哈哈),自己没遇到也没有认真的去对待他,今天,就是在今天,我打开Eclipse连上手机,准备调试程

Android开发遇到的异常及解决办法

Android开发遇到的错误及解决方法1. Unable to resolve target 'android-7' 解决方案: 修改工程目录下的default.properties文件里的内容target=android-7改成target=android-12(或者其他版本)就可以了,最好用txt打开,然后修改之后保存,运行就可以了. 原代码如下: # This file is automatically generated by Android Tools.# Do not modify

兔子--Android Support v4包丢失的解决办法

在开发中,Android Support v4包丢失的解决办法: Project->properties->Java Build Path->Libraries->Add External Jars 中加入sdk目录下的extras/android/support/v4/android-support-v4.jar (如果找不到,则需要用sdk manager下载android support package)

angularJS+Ionic移动端图片上传的解决办法

前端开发中经常会碰到图片上传的问题,网上的解决办法很多,可是有些图片上传的插件会有一些附属的插件,因此因为一个图片上传的问题可能额需要引入其他插件到项目中,久而久之项目会不伦不类,有时候插件之间也会有一些冲突,所以我们可以自己写一个图片上传的方法. 今天的demo是帮朋友做的一个移动端微信公众号项目,项目架构采用angular+ionic,因为对dom的操作jQuery会方便很多,但是jQuery比较厚重,所以最后选择用轻量级的zepto来对项目dom进行操作. 项目中有一个需求是上传个人作品,