zoukankan      html  css  js  c++  java
  • 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 )

    转:http://blog.sina.com.cn/s/blog_73e890f401016nmw.html

  • 相关阅读:
    基于nginx的rtmp的服务器(nginx-rtmp-module)
    基于nginx的HLS简单服务器搭建
    HLS(HTTP Live Streaming)协议之m3u8文件生成方式
    基于live555的一个简单RTSP服务器
    基于webrtc的多人视频会话的demo运行程序
    写给小白的Python之019:面向对象-类方法、静态方法
    写给小白的Python之018:面向对象-私有成员、@property
    写给小白的Python之017:面向对象-封装、继承、多态
    写给小白的Python之016:面向对象-魔法方法
    写给小白的Python之015:面向对象-类和对象
  • 原文地址:https://www.cnblogs.com/licomeback/p/3457756.html
Copyright © 2011-2022 走看看