【Android 内存优化】Bitmap 内存缓存 ( Bitmap 缓存策略 | LruCache 内存缓存 | LruCache 常用操作 | 工具类代码 )
文章目錄
- 一、Bitmap 內存緩存策略
- 二、LruCache 內存緩存
- 三、LruCache 常用操作
- 四、LruCache 工具類
- 五、源碼及資源下載
官方參考 : Google 官方提供的 內存優化參考 ;
Glide 開源庫 : 官方建議凡是使用到 Bitmap 解碼 , 顯示 , 緩存等操作 , 直接使用 Glide 開源庫進行上述操作 , 不建議直接操作 Bitmap 對象 ;
一、Bitmap 內存緩存策略
1 . Android 2.3.3(API 級別 10)及以下的版本中 , 使用 Bitmap 對象的 recycle 方法回收內存 ;
2 . Android 3.0(API 級別 11)及以上的版本中 , 使用新引入的 Bitmap 內存復用機制 , 通過設置 BitmapFactory.Options.inBitmap 字段 , 圖像解碼時 , 會嘗試復用該設置的 inBitmap 內存 , 該內存復用有以下限制 :
① Android 4.4(API 級別 19)及以上的版本 : 在 Android 4.4(API 級別 19)及以上的版本中 , 只要被解碼后的 Bitmap 對象的字節大小 , 小于等于 inBitmap 的字節大小 , 就可以復用成功 ; 解碼后的乳香可以是縮小后的 , 即 BitmapFactory.Options.inSampleSize 可以大于1 ;
② Android 4.4(API 級別 19)以下的版本 : 在 Android 4.4(API 級別 19) 之前的代碼中 , 復用的前提是必須同時滿足以下 333 個條件 :
- 被解碼的圖像必須是 JPEG 或 PNG 格式
- 被復用的圖像寬高必須等于 解碼后的圖像寬高
- 解碼圖像的 BitmapFactory.Options.inSampleSize 設置為 1 , 也就是不能縮放
才能復用成功 , 另外被復用的圖像的像素格式 Config ( 如 RGB_565 ) 會覆蓋設置的 BitmapFactory.Options.inPreferredConfig 參數 ;
二、LruCache 內存緩存
1 . LruCache 簡介 : 內存緩存一般使用 LruCache , 在 【Android 應用開發】LruCache 簡介 博客中有簡要介紹 ;
① LRU 算法 : LruCache 使用 LRU ( Least Recently Used 最近最少使用 ) 算法 , 其內部維護了一個 LinkedHashMap 隊列 ;
② LRU 數據淘汰原理 : 最近最少使用的數據 , 將會被淘汰 ;
③ LRU 緩存數據優先級 : 如果某數據最近被訪問過 , 那么之后的一段時間可能被訪問的幾率增加 , 其優先級提高 , 如果某數據很長時間沒有訪問 , 其優先級會被降低 ; 當 LruCache 緩存的內存數據達到了設定的緩存大小 , 低優先級的數據會被先淘汰 ;
2 . 數據結構 : 該隊列使用雙向鏈表實現 , 實際存放內存數據的是 LinkedHashMap 集合 ;
// 這是定義雜 LruCache 中的內部集合 private final LinkedHashMap<K, V> map;3 . LruCache 工作機制 :
① 獲取數據時 :
-
有緩存 : 如果 LinkedHashMap 緩存中存在該 key 對應的數據 , 那么直接返回該數據 , 并且將該數據放到隊頭 ;
-
沒有緩存 : 如果 LinkedHashMap 緩存中不存在該 key 對應的數據 , 那么需要創建該數據 , 并插入到 LinkedHashMap 中 , 并且返回該數據 ;
② 插入數據處理 :
- 緩存沒有滿 : 向 LinkedHashMap 插入數據 , 如果緩存沒有滿 , 直接將該數據插入到隊頭 ;
- 緩存滿了 : 向 LinkedHashMap 插入數據 , 如果緩存滿了, 將隊尾的若干數據移除隊列 , 然后將新數據插入到隊頭 ;
Lru 內存 緩存 , Disk 磁盤緩存參考 : JakeWharton/DiskLruCache
三、LruCache 常用操作
1 . 創建 LruCache :
① 指定內存 : 創建 LruCache 時 , 需要指定該緩存的最大內存 , 一般是 APP 可用內存的 1/8 ;
② 實現移除回調方法 : 由于內存緊張 , LruCache 將隊尾的數據移除隊列 , 會回調 entryRemoved , 可以進行一些用戶自定義的處理 ;
// 設置的內存 , 一般是 APP 可用內存的 1/8LruCache<String, Bitmap> mLruCache = new LruCache<String, Bitmap>(lruCacheMemoryByte){/*** 返回 LruCache 的鍵和值的大小 , 單位使用用戶自定義的單位* 默認的實現中 , 返回 1 ; size 是 鍵值對個數 , 最大的 size 大小是最多鍵值對個數* 鍵值對條目在 LruCache 中緩存時 , 其大小不能改變* @param key* @param value* @return 返回 LruCache<String, Bitmap> 的值 , 即 Bitmap 占用內存*/@Overrideprotected int sizeOf(String key, Bitmap value) {return value.getByteCount();}/*** 從 LruCache 緩存移除 Bitmap 時會回調該方法* @param evicted* @param key* @param oldValue* @param newValue*/@Overrideprotected void entryRemoved(boolean evicted, String key, Bitmap oldValue,Bitmap newValue) {super.entryRemoved(evicted, key, oldValue, newValue);oldValue.recycle();}};2 . LruCache 操作 :
① 存放數據 : mLruCache.put(key, value) ;
② 取出數據 : mLruCache.get(key) ;
③ 清除所有緩存數據 : mLruCache.evictAll() ;
四、LruCache 工具類
LruCache 緩存 Bitmap 工具類 :
package kim.hsl.bm.utils;import android.app.ActivityManager; import android.content.Context; import android.graphics.Bitmap; import android.util.LruCache;/*** Bitmap 內存緩存* 單純使用 LruCache 緩存圖片到內存中*/ public class BitmapLruCache {private static final String TAG = "BitmapMemoryCache";/*** 應用上下文對象*/private Context mContext;/*** 緩存圖片的 LruCache*/private LruCache<String, Bitmap> mLruCache;/*** 單例實現*/private static BitmapLruCache INSTANCE;private BitmapLruCache(){}public static BitmapLruCache getInstance(){if(INSTANCE == null){INSTANCE = new BitmapLruCache();}return INSTANCE;}/*** 使用時初始化* @param context*/public void init(Context context){// 初始化內存緩存initLruCache(context);}/*** 不使用時釋放*/public void release(){}private void initLruCache(Context context){// 為成員變量賦值this.mContext = context;// 獲取 Activity 管理器ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);// 獲取應用可用的最大內存int maxMemory = activityManager.getMemoryClass();// 獲取的 maxMemory 單位是 MB , 將其轉為字節 , 除以 8int lruCacheMemoryByte = maxMemory / 8 * 1024 * 1024;// 設置的內存 , 一般是 APP 可用內存的 1/8mLruCache = new LruCache<String, Bitmap>(lruCacheMemoryByte){/*** 返回 LruCache 的鍵和值的大小 , 單位使用用戶自定義的單位* 默認的實現中 , 返回 1 ; size 是 鍵值對個數 , 最大的 size 大小是最多鍵值對個數* 鍵值對條目在 LruCache 中緩存時 , 其大小不能改變* @param key* @param value* @return 返回 LruCache<String, Bitmap> 的值 , 即 Bitmap 占用內存*/@Overrideprotected int sizeOf(String key, Bitmap value) {return value.getByteCount();}/*** 從 LruCache 緩存移除 Bitmap 時會回調該方法* @param evicted* @param key* @param oldValue* @param newValue*/@Overrideprotected void entryRemoved(boolean evicted, String key, Bitmap oldValue,Bitmap newValue) {super.entryRemoved(evicted, key, oldValue, newValue);oldValue.recycle();}};}/*下面的 3 個方法是提供給用戶用于操作 LruCache 的接口*//*** 將鍵值對放入 LruCache 中* @param key* @param value*/public void putBitmapToLruCache(String key, Bitmap value){mLruCache.put(key, value);}/*** 從 LruCache 中獲取 Bitmap 對象* @param key* @return*/public Bitmap getBitmapFromLruCache(String key){return mLruCache.get(key);}/*** 清除 LruCache 緩存*/public void clearLruCache(){mLruCache.evictAll();}}五、源碼及資源下載
源碼及資源下載地址 :
-
① GitHub 工程地址 : BitmapMemory
-
② BitmapLruCache.java 工具類地址 : BitmapLruCache.java
總結
以上是生活随笔為你收集整理的【Android 内存优化】Bitmap 内存缓存 ( Bitmap 缓存策略 | LruCache 内存缓存 | LruCache 常用操作 | 工具类代码 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【错误记录】Android 内存泄漏 错
- 下一篇: 【Android 内存优化】Bitmap