Glide框架解析---磁盤緩存與加載器(二)

一、磁盤緩存

其實磁盤緩存的原理沒什麼好說的?爲什麼這麼說呢?因爲Glide磁盤緩存的實現使用的也是JakeWharton大神的DisLruCache,所以呢,我們也是直接拿過來用即可,直接把這三個文件直接Copy即可。下面我們來說一下磁盤緩存怎麼去使用:

首先我們先寫一個磁盤緩存用到的接口類DiskCache

public interface DiskCache {
    interface Writer {
        boolean write(File file);
    }
    File get(Key key);

    void put(Key key, Writer writer);

    void delete(Key key);

    void clear();
}

get,put,delete,clear這四個方法看名字就知道具體的作用,至於Writer和它的write方法,主要就是對圖片進行解碼,用到的時候我們具體說。下面是DiskCache的實現類DiskLruCacheWrapper:

public class DiskLruCacheWrapper implements DiskCache {
    final static int DEFAULT_DISK_CACHE_SIZE = 250 * 1024 * 1024;
    final static String DEFAULT_DISK_CACHE_DIR = "image_manager_disk_cache";
    private MessageDigest MD;
    private DiskLruCache diskLruCache;
    public DiskLruCacheWrapper(Context context) {
        this(new File(context.getCacheDir(), DEFAULT_DISK_CACHE_DIR), DEFAULT_DISK_CACHE_SIZE);
    }
    protected DiskLruCacheWrapper(File directory, long maxSize) {
        try {
            MD = MessageDigest.getInstance("SHA-256");
            //打開一個緩存目錄,如果沒有則首先創建它,
            // directory:指定數據緩存地址
            // appVersion:APP版本號,當版本號改變時,緩存數據會被清除
            // valueCount:同一個key可以對應多少文件
            // maxSize:最大可以緩存的數據量
            diskLruCache = DiskLruCache.open(directory, 1, 1, maxSize);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public String getKey(Key key) {
        key.updateDiskCacheKey(MD);
        return new String(Utils.sha256BytesToHex(MD.digest()));
    }
    @Nullable
    @Override
    public File get(Key key) {
        String k = getKey(key);
        File result = null;
        try {
            DiskLruCache.Value value = diskLruCache.get(k);
            if (value != null) {
                result = value.getFile(0);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 加入磁盤緩存
     * @param key
     * @param writer
     */
    @Override
    public void put(Key key, Writer writer) {
        String k = getKey(key);
        try {
            DiskLruCache.Value current = diskLruCache.get(k);
            if (current != null) {
                return;
            }
            DiskLruCache.Editor editor = diskLruCache.edit(k);
            try {
                File file = editor.getFile(0);
                if (writer.write(file)) {
                    editor.commit();
                }
            } finally {
                editor.abortUnlessCommitted();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void delete(Key key) {
        String k = getKey(key);
        try {
            diskLruCache.remove(k);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void clear() {
        try {
            diskLruCache.delete();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

簡單的說一下:

構造方法中主要做了一些初始化的工作,包括:計算Hash的算法名稱(我這裏用的是SHA-256),初始化磁盤緩存的位置,版本,大小等。其他的四個方法就是一些具體的操作,可以自己看看,都不難,如果有問題可以給我留言。

二、加載器

我們先看一張架構圖,然後我們再去理解這個加載器的流程

上面的架構圖並不是真正Glide的架構模式,這個是我們要寫的閹割版Glide的架構,不過流程基本沒變。

這裏的處理數據的模型只有4個,但是真正的Glide的數據處理模型有好幾十個,我這裏只拿出來幾個比較常用的來說。

我們一步一步來:

第一步:Glide在初始化的時候,都會把相應的數據處理模型註冊到ModelLoaderRegister中,模型中的Model指的是圖片資源的類型,Data指的是加載文件後的輸出類型,我這裏一律以InputStream的格式進行輸出。Factory主要就是創建相應ModelLoader來進行數據的加載(真正進行數據加載的其實是LoadData的fetcher,這個我們稍後說)。然後將這三個元素封裝在一個Entry類中,加入到ModelLoaderRegister中。

第二步:當圖片資源加入到Glide時,系統會根據資源的類型,在ModelLoaderRegister中查找,哪種數據模型可以處理這個圖片資源。當然查找的結果可能是多種,也可能是一種,所以我們使用List來裝。找到符合的數據模型後,Factory就會調用build來創建一個ModelLoader對象。比如圖片資源File類型時,找到的Factory是FileLoader.Factory,但它在build的時候,其實是ModelLoaderRegister根據Model爲Uri,Data爲InputStream進行build相應的ModelLoader(估計到這裏,好多同學就懵了。怎麼又回去了?FileLoader感覺什麼也沒做呢?是的,其實FileLoader更像是中轉站)。ModelLoaderRegister在build的時候,又會出現上面的問題,ModelLoader可能有一個,也有可能是多個,怎麼辦?我們還要保證返回值是同一類型。有的同學可能會說,可以使用List。我認爲這樣設計沒有問題。ModelLoader中都有一個buildData,方法的參數就是圖片資源,我們可以在這裏對List進行遍歷,拿出每個ModelLoader來進行handle,看看能不能處理圖片資源。但是這就要每個ModelLoader都要在這個方法中寫循環的重複代碼,很冗餘。所以Glide就創建了一個叫做MultiModelLoader的類,它也是ModelLoader,在這個類裏面有一個ModelLoader的集合。所以ModelLoaderRegister在build的時候,如果是一個則返回相應的ModelLoader;如果是多個,則統一放在MultiModelLoader的集合裏,判斷邏輯統一在MultiModelLoader的buildData方法來做。

第三步:如果圖片是網絡圖片,那麼ModelLoader最後會被定位爲HttpUriLoader,通過buildData,找對應的HttpUriFetcher進行圖片的獲取;如果圖片是本地圖片,那麼ModelLoader最後會被定位爲FileUriLoader,通過buildData,找到對應的Fetcher爲FileUriFetcher,然後進行資源的獲取。

加載器這部分很重要,但是的確很難理解,我們需要反覆的去看源碼纔可以,不是我幾句話就能說得清楚的,我這裏僅僅是拋磚引玉吧。代碼我就不貼了,類實在是不少,我會把這部分的代碼提供出來供大家研究。代碼

歡迎大家提問和糾錯!

 

 

發佈了51 篇原創文章 · 獲贊 38 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章