[轉]android端讀取本地圖片出現OutOfMemoryException

來源:互聯網
上載者:User

標籤:

前些日子一直為圖片記憶體溢出問題困擾著,查了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 )

[轉]android端讀取本地圖片出現OutOfMemoryException

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.