【Android 内存优化】Bitmap 内存缓存 ( Bitmap 内存复用 | 弱引用 | 引用队列 | 针对不同 Android 版本开发不同的 Bitmap 复用策略 | 工具类代码 )
文章目錄
- 一、Bitmap 復用池
- 二、弱引用 Bitmap 內存釋放
- 三、從 Bitmap 復用池中獲取對應可以被復用的 Bitmap 對象
- 1、Android 2.3.3(API 級別 10)及以下的版本
- 2、Android 4.4(API 級別 19)以下的版本
- 2、在 Android 4.4(API 級別 19)及以上的版本
- 四、LruCache 內存緩存、內存復用工具類
- 1、工具類
- 2、工具類測試
- 3、執行結果
- 五、源碼及資源下載
在上一篇博客 【Android 內存優化】Bitmap 內存緩存 ( Bitmap 緩存策略 | LruCache 內存緩存 | LruCache 常用操作 | 工具類代碼 ) 中 , 使用 LruCache 緩存 Bitmap 數據到內存中 , 設置其最大緩存為應用可用內存的 1/8 , 將解碼后的 Bitmap 對象緩存到 LruCache 中 , 避免重復使用該 Bitmap 對象時重復解碼加載圖片 ;
一、Bitmap 復用池
1 . Bitmap 復用池 : 加載圖片時 , 使用 inBitmap 復用選項 , 需要獲取圖片時 , 優先從 Bitmap 復用池中查找復用已存在的 Bitmap 對象 ; 假如 Bitmap 對象長時間不使用 , 就會從 LruCache 內存緩存中移除 , 此時放入到 Bitmap 復用池中 ;
2 . 弱引用 : 這里使用弱引用保存該 Bitmap , 每次 GC 時都會回收沒有被引用的 Bitmap , 需要創建一個線程安全的 HashSet , 其中的元素是 Bitmap 弱引用 ;
Set<WeakReference<Bitmap>> bitmapReusePool;二、弱引用 Bitmap 內存釋放
有一點特別注意 , Java 中的弱引用 , 在 GC 時會回收沒有使用到的內存 ; Bitmap 內存如果在 Java 層 , 可以將該內存回收 , 但是如果 Bitmap 內存在 Native 層 , 必須調用 Bitmap 對象的 recycle 方法 , 才能將內存釋放 ;
1 . Bitmap 內存放置策略 :
- 3.0 以下系統中 , Bitmap 內存在 Native 層
- 3.0 以上系統中 , Bitmap 內存在 Java 層
- 8.0 及以上的系統中 , Bitmap 內存在 Native 層
為了適配所有手機 , 所有版本 , 不管 GC 是否自動釋放 Bitmap 內存 , 在弱引用對象被回收時 , 必須手動調用一下 Bitmap 對象的 recycle 方法 ;
2 . 兼容弱引用釋放方法 : 使用引用隊列 ReferenceQueue 監控該弱引用 Bitmap 的 Set 集合元素 , 當有 Bitmap 被回收后 , 就會將其放入 ReferenceQueue 中 , 此時開啟一個線程 , 不斷從 ReferenceQueue 調用 remove 方法獲取被釋放的內存對象 , 如果獲取到了非空內容 , 說明有一個 Bitmap 弱引用對象被釋放了 , 拿到該對象引用 Reference 后 , 獲取其對應的 Bitmap 對象 , 手動調用 Bitmap 對象的 recycle 方法 , 即可完成對應操作 ;
代碼示例 :
/*** Bitmap 復用池* 使用 inBitmap 復用選項* 需要獲取圖片時 , 優先從 Bitmap 復用池中查找* 這里使用弱引用保存該 Bitmap , 每次 GC 時都會回收該 Bitmap* 創建一個線程安全的 HashSet , 其中的元素是 Bitmap 弱引用** 該 Bitmap 復用池的作用是 , 假如 Bitmap 對象長時間不使用 , 就會從內存緩存中移除** 因此這里需要處理 Bitmap 內存在 Native 層的情況 , 監控到 Java 層的弱引用被釋放了* 需要調用 Bitmap 對象的 recycle 方法 , 釋放 Native 層的內存** 需要使用引用隊列監控弱引用的釋放情況*/Set<WeakReference<Bitmap>> bitmapReusePool;/*** 引用隊列 , 用于監控 Set<WeakReference<Bitmap>> bitmapReusePool 的內存是否被回收* 需要維護一個線程 , 不斷嘗試從該引用隊列中獲取引用**/private ReferenceQueue<Bitmap> referenceQueue;/*** 監控 Set<WeakReference<Bitmap>> bitmapReusePool 的內存是否被回收 ,* 調用 ReferenceQueue<Bitmap> referenceQueue 的 remove 方法 ,* 查看是否存在被回收的弱引用 , 如果存在 , 直接回收該弱引用對應的 Bitmap 對象*/private Thread referenceQueueMonitorThread;/*** 是否持續監控引用隊列 ReferenceQueue*/private boolean isMonitorReferenceQueue = true;/*** 初始化引用隊列*/private void initBitmapReusePool(){// 創建一個線程安全的 HashSet , 其中的元素是 Bitmap 弱引用bitmapReusePool = Collections.synchronizedSet(new HashSet<WeakReference<Bitmap>>());// 引用隊列 , 當弱引用被 GC 掃描后 , 需要回收 , 會將該弱引用放入隊列// 一直不斷的嘗試從該引用隊列中獲取數據 , 如果獲取到數據 , 就要回收該對象referenceQueue = new ReferenceQueue<>();// 定義監控線程referenceQueueMonitorThread = new Thread(){@Overridepublic void run() {while (isMonitorReferenceQueue){try {Reference<Bitmap> reference = (Reference<Bitmap>) referenceQueue.remove();Bitmap bitmap = reference.get();// 不為空 , 且沒有被回收 , 回收 Bitmap 內存if(bitmap != null && !bitmap.isRecycled()){bitmap.recycle();}} catch (InterruptedException e) {e.printStackTrace();}}}};// 啟動引用隊列監控線程referenceQueueMonitorThread.start();}三、從 Bitmap 復用池中獲取對應可以被復用的 Bitmap 對象
根據不同系統版本進行不同處理 :
1、Android 2.3.3(API 級別 10)及以下的版本
Android 2.3.3(API 級別 10)及以下的版本 : 使用 Bitmap 對象的 recycle 方法回收內存 ;
// Android 2.3.3(API 級別 10)及以下的版本中 , 使用 Bitmap 對象的 recycle 方法回收內存if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1){// 如果 API 級別小于等于 10 , 不啟用 Bitmap 內存復用機制 , 返回 null 即可return null;}2、Android 4.4(API 級別 19)以下的版本
Android 4.4(API 級別 19)以下的版本 : 復用的前提是必須同時滿足以下 3 個條件 :
- 被解碼的圖像必須是 JPEG 或 PNG 格式
- 被復用的圖像寬高必須等于 解碼后的圖像寬高
- 解碼圖像的 BitmapFactory.Options.inSampleSize 設置為 1 , 也就是不能縮放
才能復用成功 , 另外被復用的圖像的像素格式 Config ( 如 RGB_565 ) 會覆蓋設置的 BitmapFactory.Options.inPreferredConfig 參數 ;
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2){/*Android 4.4(API 級別 19)以下的版本 : 在 Android 4.4(API 級別 19) 之前的代碼中 ,復用的前提是必須同時滿足以下 3 個條件 :1. 被解碼的圖像必須是 JPEG 或 PNG 格式2. 被復用的圖像寬高必須等于 解碼后的圖像寬高3. 解碼圖像的 BitmapFactory.Options.inSampleSize 設置為 1 , 也就是不能縮放才能復用成功 , 另外被復用的圖像的像素格式 Config ( 如 RGB_565 ) 會覆蓋設置的BitmapFactory.Options.inPreferredConfig 參數 ;*/if(bitmap.getWidth() == width &&bitmap.getHeight() == height && //被復用的圖像寬高必須等于 解碼后的圖像寬高inSampleSize == 1){// 圖像的 BitmapFactory.Options.inSampleSize 設置為 1//符合要求inBitmap = bitmap;iterator.remove();}}2、在 Android 4.4(API 級別 19)及以上的版本
在 Android 4.4(API 級別 19)及以上的版本 : 只要被解碼后的 Bitmap 對象的字節大小 , 小于等于 inBitmap 的字節大小 , 就可以復用成功 ; 解碼后的乳香可以是縮小后的 , 即 BitmapFactory.Options.inSampleSize 可以大于1 ;
}else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){/*在 Android 4.4(API 級別 19)及以上的版本中 ,只要被解碼后的 Bitmap 對象的字節大小 , 小于等于 inBitmap 的字節大小 , 就可以復用成功 ;解碼后的乳香可以是縮小后的 , 即 BitmapFactory.Options.inSampleSize 可以大于1 ;*/// 首先要計算圖像的內存占用 , 先要計算出圖像的寬高 , 如果圖像需要縮放 , 計算縮放后的寬高if(inSampleSize > 1){width = width / inSampleSize ;height = height / inSampleSize;}// 計算內存占用 , 默認 ARGB_8888 格式int byteInMemory = width * height * 4;;if(bitmap.getConfig() == Bitmap.Config.ARGB_8888){// 此時每個像素占 4 字節byteInMemory = width * height * 4;}else if(bitmap.getConfig() == Bitmap.Config.RGB_565){// 此時每個像素占 2 字節byteInMemory = width * height * 2;}// 如果解碼后的圖片內存小于等于被復用的內存大小 , 可以復用if(byteInMemory <= bitmap.getAllocationByteCount()){//符合要求inBitmap = bitmap;iterator.remove();}}四、LruCache 內存緩存、內存復用工具類
1、工具類
BitmapLruCacheMemoryReuse.java 工具類地址 : BitmapLruCacheMemoryReuse.java
package kim.hsl.bm.utils;import android.app.ActivityManager; import android.content.Context; import android.graphics.Bitmap; import android.os.Build; import android.util.LruCache;import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set;/*** Bitmap 內存緩存* 在將圖片緩存到 LruCache 內存中基礎上 ,* 將從 LruCache 中移除的最近沒有使用的 Bitmap 對象的內存復用* 這樣能最大限度減少內存抖動*/ public class BitmapLruCacheMemoryReuse {private static final String TAG = "BitmapMemoryCache";/*** 應用上下文對象*/private Context mContext;/*** 緩存圖片的 LruCache*/private LruCache<String, Bitmap> mLruCache;/*** Bitmap 復用池* 使用 inBitmap 復用選項* 需要獲取圖片時 , 優先從 Bitmap 復用池中查找* 這里使用弱引用保存該 Bitmap , 每次 GC 時都會回收該 Bitmap* 創建一個線程安全的 HashSet , 其中的元素是 Bitmap 弱引用** 該 Bitmap 復用池的作用是 , 假如 Bitmap 對象長時間不使用 , 就會從內存緩存中移除** Bitmap 回收策略 :* 3.0 以下系統中 , Bitmap 內存在 Native 層* 3.0 以上系統中 , Bitmap 內存在 Java 層* 8.0 及以上的系統中 , Bitmap 內存在 Native 層** 因此這里需要處理 Bitmap 內存在 Native 層的情況 , 監控到 Java 層的弱引用被釋放了* 需要調用 Bitmap 對象的 recycle 方法 , 釋放 Native 層的內存** 需要使用引用隊列監控弱引用的釋放情況*/Set<WeakReference<Bitmap>> bitmapReusePool;/*** 引用隊列 , 用于監控 Set<WeakReference<Bitmap>> bitmapReusePool 的內存是否被回收* 需要維護一個線程 , 不斷嘗試從該引用隊列中獲取引用**/private ReferenceQueue<Bitmap> referenceQueue;/*** 監控 Set<WeakReference<Bitmap>> bitmapReusePool 的內存是否被回收 ,* 調用 ReferenceQueue<Bitmap> referenceQueue 的 remove 方法 ,* 查看是否存在被回收的弱引用 , 如果存在 , 直接回收該弱引用對應的 Bitmap 對象*/private Thread referenceQueueMonitorThread;/*** 是否持續監控引用隊列 ReferenceQueue*/private boolean isMonitorReferenceQueue = true;/*** 單例實現*/private static BitmapLruCacheMemoryReuse INSTANCE;private BitmapLruCacheMemoryReuse(){}public static BitmapLruCacheMemoryReuse getInstance(){if(INSTANCE == null){INSTANCE = new BitmapLruCacheMemoryReuse();}return INSTANCE;}/*** 使用時初始化* @param context*/public void init(Context context){// 初始化內存緩存initLruCache(context);// 初始化弱引用隊列initBitmapReusePool();}/*** 不使用時釋放*/public void release(){isMonitorReferenceQueue = false;}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) {// 如果使用的是復用的 Bitmap 對象 , 其占用內存大小是之前的圖像分配的內存大小// 大于等于當前圖像的內存占用大小if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {return value.getAllocationByteCount();}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);/*如果從 LruCache 內存緩存中移除的 Bitmap 是可變的才能被復用 , 否則只能回收該 Bitmap 對象Bitmap 回收策略 :3.0 以下系統中 , Bitmap 內存在 Native 層3.0 以上系統中 , Bitmap 內存在 Java 層8.0 及以上的系統中 , Bitmap 內存在 Native 層因此這里需要處理 Bitmap 內存在 Native 層的情況 , 監控到 Java 層的弱引用被釋放了需要調用 Bitmap 對象的 recycle 方法 , 釋放 Native 層的內存*/if(oldValue.isMutable()){ // 可以被復用// 將其放入弱引用中 , 每次 GC 啟動后 , 如果該弱引用沒有被使用 , 都會被回收bitmapReusePool.add(new WeakReference<Bitmap>(oldValue, referenceQueue));}else{ // 不可被復用 , 直接回收oldValue.recycle();}}};}private void initBitmapReusePool(){// 創建一個線程安全的 HashSet , 其中的元素是 Bitmap 弱引用bitmapReusePool = Collections.synchronizedSet(new HashSet<WeakReference<Bitmap>>());// 引用隊列 , 當弱引用被 GC 掃描后 , 需要回收 , 會將該弱引用放入隊列// 一直不斷的嘗試從該引用隊列中獲取數據 , 如果獲取到數據 , 就要回收該對象referenceQueue = new ReferenceQueue<>();// 定義監控線程referenceQueueMonitorThread = new Thread(){@Overridepublic void run() {while (isMonitorReferenceQueue){try {Reference<Bitmap> reference = (Reference<Bitmap>) referenceQueue.remove();Bitmap bitmap = reference.get();// 不為空 , 且沒有被回收 , 回收 Bitmap 內存if(bitmap != null && !bitmap.isRecycled()){bitmap.recycle();}} catch (InterruptedException e) {e.printStackTrace();}}}};// 啟動引用隊列監控線程referenceQueueMonitorThread.start();}/*** 獲取一個可以被復用的 Bitmap 對象** 與 BitmapFactory 配合使用 :** Android 4.4 以后的 Bitmap 復用情況 :* 在 KITKAT ( Android 4.4 , 19 平臺 ) 以后的代碼中 ,* 只要被解碼生成的 Bitmap 對象的字節大小 ( 縮放后的 )* 小于等于 inBitmap 的字節大小 , 就可以復用成功 ;** Android 4.4 之前的 Bitmap 復用情況 : ( 比較苛刻 )* 在 KITKAT 之前的代碼中 , 被解碼的圖像必須是* - JPEG 或 PNG 格式 ,* - 并且 圖像大小必須是相等的 ,* - inssampleSize 設置為 1 ,* 才能復用成功 ;* 另外被復用的圖像的 像素格式 Config ( 如 RGB_565 ) 會覆蓋設置的 inPreferredConfig 參數** @param width* @param height* @param inSampleSize* @return*/public Bitmap getReuseBitmap(int width,int height,int inSampleSize){// Android 2.3.3(API 級別 10)及以下的版本中 , 使用 Bitmap 對象的 recycle 方法回收內存if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1){// 如果 API 級別小于等于 10 , 不啟用 Bitmap 內存復用機制 , 返回 null 即可return null;}// 獲取準備復用的 Bitmap , 之后設置到 Options 中Bitmap inBitmap = null;// 使用迭代器遍歷該 Set 集合 , 如果遍歷中涉及到刪除 , 就要使用迭代器遍歷Iterator<WeakReference<Bitmap>> iterator = bitmapReusePool.iterator();//迭代查找符合復用條件的Bitmapwhile (iterator.hasNext()){// 循環遍歷 Bitmap 對象Bitmap bitmap = iterator.next().get();if (bitmap != null){/*檢查該 Bitmap 對象是否可以達到復用要求 ,如果達到復用要求 , 就取出這個 Bitmap 對象 , 并將其從隊列中移除*/if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2){/*Android 4.4(API 級別 19)以下的版本 : 在 Android 4.4(API 級別 19) 之前的代碼中 ,復用的前提是必須同時滿足以下 3 個條件 :1. 被解碼的圖像必須是 JPEG 或 PNG 格式2. 被復用的圖像寬高必須等于 解碼后的圖像寬高3. 解碼圖像的 BitmapFactory.Options.inSampleSize 設置為 1 , 也就是不能縮放才能復用成功 , 另外被復用的圖像的像素格式 Config ( 如 RGB_565 ) 會覆蓋設置的BitmapFactory.Options.inPreferredConfig 參數 ;*/if(bitmap.getWidth() == width &&bitmap.getHeight() == height && //被復用的圖像寬高必須等于 解碼后的圖像寬高inSampleSize == 1){// 圖像的 BitmapFactory.Options.inSampleSize 設置為 1//符合要求inBitmap = bitmap;iterator.remove();}}else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){/*在 Android 4.4(API 級別 19)及以上的版本中 ,只要被解碼后的 Bitmap 對象的字節大小 , 小于等于 inBitmap 的字節大小 , 就可以復用成功 ;解碼后的乳香可以是縮小后的 , 即 BitmapFactory.Options.inSampleSize 可以大于1 ;*/// 首先要計算圖像的內存占用 , 先要計算出圖像的寬高 , 如果圖像需要縮放 , 計算縮放后的寬高if(inSampleSize > 1){width = width / inSampleSize ;height = height / inSampleSize;}// 計算內存占用 , 默認 ARGB_8888 格式int byteInMemory = width * height * 4;;if(bitmap.getConfig() == Bitmap.Config.ARGB_8888){// 此時每個像素占 4 字節byteInMemory = width * height * 4;}else if(bitmap.getConfig() == Bitmap.Config.RGB_565){// 此時每個像素占 2 字節byteInMemory = width * height * 2;}// 如果解碼后的圖片內存小于等于被復用的內存大小 , 可以復用if(byteInMemory <= bitmap.getAllocationByteCount()){//符合要求inBitmap = bitmap;iterator.remove();}}}else if( bitmap == null ){// 如果 bitmap 為空 , 直接從復用 Bitmap 集合中移除iterator.remove();}}return inBitmap;}/*下面的 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();} }2、工具類測試
package kim.hsl.bm;import androidx.appcompat.app.AppCompatActivity;import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.Log; import android.widget.TextView;import kim.hsl.bm.utils.BitmapLruCacheMemoryReuse; import kim.hsl.bm.utils.BitmapSizeReduce;public class MainActivity extends AppCompatActivity {static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TextView tv = findViewById(R.id.sample_text);tv.setText(stringFromJNI());// 內存緩存memoryCache();}/*** 圖像緩存*/private void memoryCache(){// 初始化 LruCache 內存緩存 , 與引用隊列 , 一般在 onCreate 方法中初始化// 這里為了演示 , 放在方法的開頭位置BitmapLruCacheMemoryReuse.getInstance().init(this);// 第一次從 LruCache 內存中獲取 Bitmap 數據Bitmap bitmap = BitmapLruCacheMemoryReuse.getInstance().getBitmapFromLruCache(R.drawable.blog + "");/*如果從內存中獲取 Bitmap 對象失敗 , 這里就需要創建該圖片 , 并放入 LruCache 內存中*/if(bitmap == null){// 要復用內存的 Bitmap 對象 , 將新的 Bitmap 寫入到該 Bitmap 內存中Bitmap inBitmap = null;// 嘗試獲取復用對象BitmapLruCacheMemoryReuse.getInstance().getReuseBitmap(200, 200, 1);// 加載指定大小格式的圖像bitmap = BitmapSizeReduce.getResizedBitmap(this, R.drawable.blog,200, 200, false, inBitmap);// 將新的 bitap 放入 LruCache 內存緩存中BitmapLruCacheMemoryReuse.getInstance().putBitmapToLruCache(R.drawable.blog + "", bitmap);Log.i("Bitmap 沒有獲取到創建新的", "blog : " + bitmap.getWidth() + " , " +bitmap.getHeight() + " , " +bitmap.getByteCount());}else{Log.i("Bitmap 內存中獲取數據", "blog : " + bitmap.getWidth() + " , " +bitmap.getHeight() + " , " +bitmap.getByteCount());}// 第一次從 LruCache 內存中獲取 Bitmap 數據Bitmap bitmap2 = BitmapLruCacheMemoryReuse.getInstance().getBitmapFromLruCache(R.drawable.blog + "");Log.i("Bitmap 第二次內存中獲取數據", "blog : " + bitmap2.getWidth() + " , " +bitmap2.getHeight() + " , " +bitmap2.getByteCount());}
3、執行結果
執行結果 : 第一次嘗試從 LruCache 中獲取圖像 , 沒有獲取到 , 創建新的 Bitmap 放入 LruCache 中 , 第二次獲取直接從 LruCache 中獲取到了圖像 ;
2020-07-02 15:15:48.300 5133-5133/kim.hsl.bm W/BitmapSizeReduce: getResizedBitmap options.outWidth=1990 , options.outHeight=1020 2020-07-02 15:15:48.300 5133-5133/kim.hsl.bm W/BitmapSizeReduce: getResizedBitmap inSampleSize=16 2020-07-02 15:15:48.327 5133-5133/kim.hsl.bm I/Bitmap 沒有獲取到創建新的: blog : 124 , 63 , 15624 2020-07-02 15:15:48.328 5133-5133/kim.hsl.bm I/Bitmap 第二次內存中獲取數據: blog : 124 , 63 , 15624五、源碼及資源下載
源碼及資源下載地址 :
-
① GitHub 工程地址 : BitmapMemory
-
② BitmapLruCacheMemoryReuse.java 工具類地址 : BitmapLruCacheMemoryReuse.java
總結
以上是生活随笔為你收集整理的【Android 内存优化】Bitmap 内存缓存 ( Bitmap 内存复用 | 弱引用 | 引用队列 | 针对不同 Android 版本开发不同的 Bitmap 复用策略 | 工具类代码 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 内存优化】Bitmap
- 下一篇: 【Android 内存优化】Bitmap