android 載入圖片輕鬆避免OOM(out of memory)
在使用android載入圖片的時候,經常會出現記憶體溢位,主要是由於android可使用的記憶體太小,而通過程式碼載入進來的圖片,並不會被GC回收,於是我寫了一個工具類用來載入圖片,並且建立快取,輕鬆避免記憶體溢位,廢話不多說,上程式碼
- package l.test1.util;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.LinkedList;
- import java.util.Map;
- import java.util.Queue;
- import java.util.Set;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.BitmapFactory.Options;
- /**
- * Bitmap工具類,快取用過的指定數量的圖片,使用此工具類,不再需要手動管理Bitmap記憶體 原理:
- * 用一個佇列儲存使用Bitmap的順序,每次使用Bitmap將物件移動到佇列頭 當記憶體不夠,或者達到制定的快取數量的時候,回收佇列尾部圖片
- * 保證當前使用最多的圖片得到最長時間的快取,提高速度
- *
- * @author liaoxingliao
- *
- */
- 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];
- private static final LinkedList<String> CACHE_ENTRIES = new LinkedList<String>(); // 此物件用來保持Bitmap的回收順序,保證最後使用的圖片被回收
- private static final Queue<QueueEntry> TASK_QUEUE = new LinkedList<QueueEntry>(); // 執行緒請求建立圖片的佇列
- private static final Set<String> TASK_QUEUE_INDEX = new HashSet<String>(); // 儲存佇列中正在處理的圖片的key,有效防止重複新增到請求建立佇列
- private static final Map<String, Bitmap> IMG_CACHE_INDEX = new HashMap<String, Bitmap>(); // 快取Bitmap
- // 通過圖片路徑,圖片大小
- private static int CACHE_SIZE = 200; // 快取圖片數量
- 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);
- //修正過的程式碼
- getBitmap(entry.path,entry.width,entry.height);
- }
- }
- }.start();
- }
- /**
- * 建立一張圖片 如果快取中已經存在,則返回快取中的圖,否則建立一個新的物件,並加入快取
- * 寬度,高度,為了縮放原圖減少記憶體的,如果輸入的寬,高,比原圖大,返回原圖
- *
- * @param path 圖片物理路徑 (必須是本地路徑,不能是網路路徑)
- * @param width 需要的寬度
- * @param height 需要的高度
- * @return
- */
- public static Bitmap getBitmap(String path, int width, int height) {
- 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 getBitmap(path, width, height);
- }
- return bitMap;
- }
- /**
- * 設定快取圖片數量 如果輸入負數,會產生異常
- *
- * @param size
- */
- public static void setCacheSize(int size) {
- if (size <= 0) {
- throw new RuntimeException("size :" + size);
- }
- while (size < CACHE_ENTRIES.size()) {
- destoryLast();
- }
- CACHE_SIZE = size;
- }
- /**
- * 加入一個圖片處理請求到圖片建立佇列
- *
- * @param path
- * 圖片路徑(本地)
- * @param width
- * 圖片寬度
- * @param height
- * 圖片高度
- */
- public static void addTask(String path, int width, int height) {
- QueueEntry entry = new QueueEntry();
- entry.path = path;
- entry.width = width;
- entry.height = height;
- synchronized (TASK_QUEUE) {
- String key = createKey(path, width, height);
- if (!TASK_QUEUE_INDEX.contains(key)
- && !IMG_CACHE_INDEX.containsKey(key)) {
- TASK_QUEUE.add(entry);
- TASK_QUEUE_INDEX.add(key);
- TASK_QUEUE.notify();
- }
- }
- }
- /**
- * 通過圖片路徑返回圖片實際大小
- * @param path 圖片物理路徑
- * @return
- */
- 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) {
- e.printStackTrace();
- } finally {
- closeInputStream(in);
- }
- }
- return null;
- }
- // 關閉輸入流
- private static void closeInputStream(InputStream in) {
- if (null != in) {
- try {
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- // 圖片大小
- 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;
- }
- }
相關文章
- OOM(Out Of Memory)OOM
- OOM--OUT OF MEMORYOOM
- Android載入圖片導致記憶體溢位(Out of Memory異常)Android記憶體溢位
- OOM(Out Of Memory)是什麼?OOM
- Android高效載入大圖、多圖解決方案,有效避免程式OOMAndroid圖解OOM
- 原來OOM的罪魁禍首是C程式碼---android out of memory(OOM)OOMC程式Android
- Android OOM 排查與解決——圖片載入優化AndroidOOM優化
- Android之批量載入圖片OOM問題解決方案AndroidOOM
- Webpack輕鬆入門(三)——圖片打包Web
- Android 載入大圖片時報OOM的解決方案(原始碼)AndroidOOM原始碼
- Android 圖片載入框架Android框架
- android 載入大量圖片Android
- Android 載入大圖片,不壓縮圖片Android
- Android 高效安全載入圖片Android
- 輕鬆復現一張AI圖片AI
- android glide圖片載入框架AndroidIDE框架
- 圖片三級快取及OOM--android快取OOMAndroid
- Android自定義View之圖片外形特效——輕鬆實現圓角和圓形圖片AndroidView特效
- 跟著教程做主圖,教你輕鬆去除圖片背景!
- Android ImageLoader框架之圖片載入與載入策略Android框架
- Android 基礎之圖片載入(二)Android
- Android偽圖片載入進度效果Android
- Android處理圖片OOM的若干方法小結AndroidOOM
- java out of memoryJava
- 如何輕鬆識別圖片文字?請看教程
- Android 載入網路圖片 以及實現圓角圖片效果Android
- Android圖片載入框架Fresco使用詳解Android框架
- [原]Android官方圖片載入利器BitmapFun解析Android
- Android實現圖片非同步載入操作Android非同步
- FaceBook推出的Android圖片載入庫FrescoAndroid
- Android圖片載入庫Picasso原始碼分析Android原始碼
- Flutter 圖片載入Flutter
- 圖片懶載入
- 預載入圖片
- 圖片載入事件事件
- 載入圖片方式
- Mac圖片摳圖軟體InPixio Photo Cutter輕鬆摳圖Mac
- Android Loader 機制,讓你的資料載入更加輕鬆Android