android中圖片的三級cache策略(記憶體、檔案、網路)之二:記憶體緩衝策略

來源:互聯網
上載者:User

前言

記得很久之前我寫了一篇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();    }}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.