目前第三方的圖檔加載庫很多,例如:universal-image-loader,Volley等,今天我們來寫一個簡單的圖檔加載庫實作圖檔網絡下載下傳緩存。
首先先了解一下圖檔加載用什麼方式,通常我們從網絡加載圖檔的時候希望加載的圖檔優先從本地緩存擷取,本地沒有就從網絡下載下傳再緩存到本地,這樣可以減少網絡通路的開銷和提高圖檔加載的速度,進而增加使用者體驗。
本地的緩存資源可以儲存在記憶體和本地檔案中,那麼圖檔的加載流程優先級由高到低是:從記憶體中擷取--從本地緩存檔案中擷取--從網絡擷取。
我們記憶體緩存使用的是 LruCache,檔案緩存使用的是DiskLruCache 或者 File 類。
注意:以前也有使用軟引用和弱引用實作圖檔緩存,但這種方式從API 9 開始起不了作用了。垃圾回收器會更傾向于回收持有軟引用或弱引用的對象,這讓軟引用和弱引用變得不再可靠。
一、LruCache
這個類是android 3.1 提供的,之前的舊版本需要使用android-support-v4 支援庫才能使用。LruCache使用一個LinkedHashMap簡單的實作記憶體的緩存,沒有軟引用,都是強引用。
下面看看LruCache怎樣使用
(1)建立LruCache對象
mMemoryCache = new LruCache<String, Bitmap>(maxCacheSize) {
// 必須重寫此方法,來測量Bitmap的大小
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
LruCache的構造方法傳入的參數是指定緩存的大小,如果添加的資料大于設定的最大值,就删除最先緩存的資料來調整記憶體。重寫的方法sizeof是計算圖檔的大小。
(2)添加圖檔緩存
//添加Bitmap到記憶體緩存
mMemoryCache.put(key, bitmap);
key的值用于取出對應的圖檔緩存用的。
(3)擷取圖檔緩存
//從記憶體緩存中擷取一個Bitmap
mMemoryCache.get(key);
LruCache的方法不多,用的最多的是添加和擷取的方法了,總的來說LruCache 的使用還是比較簡單的。
二、DiskLruCache
DiskLruCache 硬碟緩存,DiskLruCache 并不在 Android API 中,我們需要在網上下載下傳源碼檔案,把源碼檔案放到我們的工程裡,記得改源碼檔案的包路徑。
添加DiskLruCache 類到工程裡面之後,看看它是怎麼用的
(1)建立 DiskLruCache
DiskLruCache的建立需要調用它的靜态方法open
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize);
該方法的參數有4個:
directory ---- 資料的緩存路徑
appVersion ---- 目前應用程式的版本号
valueCount ---- 指定同一個key可以對應多少個緩存檔案,基本都是傳1
maxSize ---- 最多可以緩存多少位元組的資料
例子:
/**
* 初始化 DiskLruCache
*/
private void initDiskLruCache() {
try {
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
try {
diskLruCache = DiskLruCache.open(new File(getCacheStoragePath()), info.versionCode, 1,
config.disCacheSize);
} catch (IOException e) {
e.printStackTrace();
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
(2)擷取緩存檔案資源
DiskLruCache.Snapshot snapShot = diskLruCache.get(subUrl);
if (snapShot != null) {
FileInputStream fileInputStream = (FileInputStream) snapShot.getInputStream(0);
// 從流中轉成Bitmap對象
bitmap = BitmapFactory.decodeStream(fileInputStream);
...
} else {
Log.i("load", "手機存儲中沒有");
}
(3)儲存緩存檔案
先擷取 DiskLruCache.Editor 對象
DiskLruCache.Editor editor = diskLruCache.edit(key);//參數 key 是緩存檔案的檔案名
if (editor != null) {
//從Editor 擷取緩存的輸出流
OutputStream outputStream = editor.newOutputStream(0);
//把資料儲存成檔案
bitmap.compress(config.compressFormat, config.imageQuality, outputStream);
//commit 送出
editor.commit();
...
}
其它的操作:
diskLruCache.delete(); 删除全部緩存檔案
diskLruCache.flush();
diskLruCache.close(); 關閉緩存
diskLruCache.remove(key); 移除key對應的緩存
diskLruCache.size() 緩存的大小
diskLruCache.getDirectory() 緩存目錄
diskLruCache.isClosed() 緩存是否關閉
三、設計圖檔加載庫
設計的目标:
(1)加載流程 :從記憶體中擷取--從本地緩存檔案中擷取--從網絡擷取
(2)線程池
(3)LruCache 負責記憶體緩存,DiskLruCache 負責硬碟緩存。
具體的源碼:
https://github.com/StarsAaron/Imageloder.git