Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android中圖片的三級cache策略(內存、文件、網絡)之二:內存緩存策略

android中圖片的三級cache策略(內存、文件、網絡)之二:內存緩存策略

編輯:關於Android編程

前言

記得很久之前我寫了一篇banner的文章,好多朋友找我要代碼,並要我開放banner中使用的圖片管理工廠-ImageManager。如果想很好地理解下面的故事,請參看我半年前寫的兩篇博文:android中圖片的三級cache策略(內存、文件、網絡) 一和android中左右滑屏的實現(廣告位banner組件)。

當時沒有發上來是由於如下幾點原因:首先代碼較多,其次當時寫的時候也參考了網絡上存在的三級cache策略(大同小異),並且采用了Android項目中開源的LruCache頁面淘汰算法(近期最少使用算法),還有一點就是這是實際項目使用的代碼,不便直接開放,但是現在我決定把它稍作修改後開放給大家。這裡我想說說那個banner,平心而論,banner的代碼很多,如果采用ViewPager之類的則可以減少不少代碼,但是我更看重banner的實現思想以及它的封裝和事件傳遞,在自定義控件的封裝和架構上,我到現在還覺得banner是及其成功的,尤其是banner和ImageManager結合以後,整個功能渾然天成,超高內聚,使用起來及其方便,最少只需要兩行代碼,你不需要導入xml,也不需要處理Json拉取策略,因為相關業務層都被封裝在了banner內部,對外只保留很少的幾個接口,只要實現它就能和banner內部進行交互。下面我將要介紹三級cache策略之二:內存緩存策略。

內存緩存策略

當有一個圖片要去從網絡下載的時候,我們並不會直接去從網絡下載,因為在這個時代,用戶的流量是寶貴的,耗流量的應用是不會得到用戶的青睐的。那我們該怎麼辦呢?這樣,我們會先從內存緩存中去查找是否有該圖片,如果沒有就去文件緩存中查找是否有該圖片,如果還沒有,我們就從網絡下載圖片。本博文的側重點是如何做內存緩存。這裡,我有必要說明下幾個概念:強引用、軟引用、弱引用、Lru。

強引用:就是直接引用一個對象,一般的對象引用均是強引用

軟引用:引用一個對象,當內存不足並且除了我們的引用之外沒有其他地方引用此對象的情況 下,該對象會被gc回收

弱引用:引用一個對象,當除了我們的引用之外沒有其他地方引用此對象的情況下,只要gc被調用,它就會被回收(請注意它和軟引用的區別)

Lru:Least Recently Used 近期最少使用算法,是一種頁面置換算法,其思想是在緩存的頁面數目固定的情況下,那些最近使用次數最少的頁面將被移出,對於我們的內存緩存來說,強引用緩存大小固定為4M,如果當緩存的圖片大於4M的時候,有些圖片就會被從強引用緩存中刪除,哪些圖片會被刪除呢,就是那些近期使用次數最少的圖片。

代碼

public class ImageMemoryCache {
    /**
     * 從內存讀取數據速度是最快的,為了更大限度使用內存,這裡使用了兩層緩存。
     *  強引用緩存不會輕易被回收,用來保存常用數據,不常用的轉入軟引用緩存。
     */
    private static final String TAG = "ImageMemoryCache";

    private static LruCache mLruCache; // 強引用緩存

    private static LinkedHashMap> mSoftCache; // 軟引用緩存

    private static final int LRU_CACHE_SIZE = 4 * 1024 * 1024; // 強引用緩存容量:4MB

    private static final int SOFT_CACHE_NUM = 20; // 軟引用緩存個數

    // 在這裡分別初始化強引用緩存和弱引用緩存
    public ImageMemoryCache() {
        mLruCache = new LruCache(LRU_CACHE_SIZE) {
            @Override
            // sizeOf返回為單個hashmap value的大小
            protected int sizeOf(String key, Bitmap value) {
                if (value != null)
                    return value.getRowBytes() * value.getHeight();
                else
                    return 0;
            }

            @Override
            protected void entryRemoved(boolean evicted, String key,
                    Bitmap oldValue, Bitmap newValue) {
                if (oldValue != null) {
                    // 強引用緩存容量滿的時候,會根據LRU算法把最近沒有被使用的圖片轉入此軟引用緩存
                    Logger.d(TAG, "LruCache is full,move to SoftRefernceCache");
                    mSoftCache.put(key, new SoftReference(oldValue));
                }
            }
        };

        mSoftCache = new LinkedHashMap>(
                SOFT_CACHE_NUM, 0.75f, true) {
            private static final long serialVersionUID = 1L;

            /**
             * 當軟引用數量大於20的時候,最舊的軟引用將會被從鏈式哈希表中移出
             */
            @Override
            protected boolean removeEldestEntry(
                    Entry> eldest) {
                if (size() > SOFT_CACHE_NUM) {
                    Logger.d(TAG, "should remove the eldest from SoftReference");
                    return true;
                }
                return false;
            }
        };
    }

    /**
     * 從緩存中獲取圖片
     */
    public Bitmap getBitmapFromMemory(String url) {
        Bitmap bitmap;

        // 先從強引用緩存中獲取
        synchronized (mLruCache) {
            bitmap = mLruCache.get(url);
            if (bitmap != null) {
                // 如果找到的話,把元素移到LinkedHashMap的最前面,從而保證在LRU算法中是最後被刪除
                mLruCache.remove(url);
                mLruCache.put(url, bitmap);
                Logger.d(TAG, "get bmp from LruCache,url=" + url);
                return bitmap;
            }
        }

        // 如果強引用緩存中找不到,到軟引用緩存中找,找到後就把它從軟引用中移到強引用緩存中
        synchronized (mSoftCache) {
            SoftReference bitmapReference = mSoftCache.get(url);
            if (bitmapReference != null) {
                bitmap = bitmapReference.get();
                if (bitmap != null) {
                    // 將圖片移回LruCache
                    mLruCache.put(url, bitmap);
                    mSoftCache.remove(url);
                    Logger.d(TAG, "get bmp from SoftReferenceCache, url=" + url);
                    return bitmap;
                } else {
                    mSoftCache.remove(url);
                }
            }
        }
        return null;
    }

    /**
     * 添加圖片到緩存
     */
    public void addBitmapToMemory(String url, Bitmap bitmap) {
        if (bitmap != null) {
            synchronized (mLruCache) {
                mLruCache.put(url, bitmap);
            }
        }
    }

    public void clearCache() {
        mSoftCache.clear();
    }
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved