Universal-Image-Loader解析系列
Universal-Image-Loader解析(一)基本介紹與使用
Universal-Image-Loader解析(二)內(nèi)部緩存原理
Universal-Image-Loader解析(三)源代碼解析
前篇文章則跟大家介紹了UIL的一些常用用法。
對(duì)于我們所知道的緩存霞篡,常用的是內(nèi)存緩存MemoryCache和硬盤緩存DiscCache玛追。一個(gè)讀取快容量小但两,一個(gè)讀取慢容量大胳施。
對(duì)于各自使用哪種緩存奇适,則可以在前面配置ImageLoaderConfiguration
進(jìn)行緩存設(shè)置谜酒,當(dāng)然也可以自己自定義適合的緩存叹俏。
ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)
.memoryCache(new WeakMemoryCache())
.build();
對(duì)于Universal-Image-Loader來(lái)說(shuō)它的緩存結(jié)構(gòu)也是分為內(nèi)存緩存MemoryCache和硬盤緩存DiskCache
一.MemoryCache內(nèi)存緩存
首先先看個(gè)結(jié)構(gòu)圖,理解UIL里面內(nèi)存緩存的結(jié)構(gòu)
由于空間有限就沒畫成標(biāo)準(zhǔn)的UML類圖形式僻族。
對(duì)于基類MemoryCache
它則是一個(gè)接口粘驰,里面定義了put,get圖片的方法
public interface MemoryCache {
...
boolean put(String key, Bitmap value);
Bitmap get(String key);
Bitmap remove(String key);
Collection<String> keys();
void clear();
}
都是大家比較所熟悉的方法,而對(duì)于其他的類
我們一個(gè)個(gè)看
LruMemoryCache
這個(gè)類就是這個(gè)開源框架默認(rèn)的內(nèi)存緩存類述么,緩存的是bitmap的強(qiáng)引用蝌数。直接實(shí)現(xiàn)了MemoryCache
方法
public class LruMemoryCache implements MemoryCache {
private final LinkedHashMap<String, Bitmap> map;
//最大容量
private final int maxSize;
/** 目前緩存的容量大小 */
private int size;
public LruMemoryCache(int maxSize) {
...
this.maxSize = maxSize;
this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
}
@Override
public final Bitmap get(String key) {
...
synchronized (this) {
return map.get(key);
}
}
@Override
public final boolean put(String key, Bitmap value) {
...
synchronized (this) {
size += sizeOf(key, value);
Bitmap previous = map.put(key, value);
if (previous != null) {
size -= sizeOf(key, previous);
}
}
trimToSize(maxSize);
return true;
}
/**
* Lru算法,當(dāng)容量超過(guò)最大緩存容量度秘,則移除最久的條目
*/
private void trimToSize(int maxSize) {
while (true) {
String key;
Bitmap value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");
}
if (size <= maxSize || map.isEmpty()) {
break;
}
Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= sizeOf(key, value);
}
}
}
@Override
public final Bitmap remove(String key) {
...
synchronized (this) {
Bitmap previous = map.remove(key);
if (previous != null) {
size -= sizeOf(key, previous);
}
return previous;
}
}
...
//返回圖片的字節(jié)大小
private int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
...
}
LruMemoryCache
的源碼也比較簡(jiǎn)單顶伞,內(nèi)部有個(gè)成員變量LinkedHashMap<String, Bitmap> map
這里直接進(jìn)行保存的話則是強(qiáng)引用的形式。
主要看get,put方法剑梳。
對(duì)于get方法來(lái)說(shuō)唆貌,比較簡(jiǎn)單,直接根據(jù)指定的key返回對(duì)應(yīng)的圖片垢乙。
而對(duì)于put方法來(lái)說(shuō)锨咙,則需要考慮容量的問題。
@Override
public final boolean put(String key, Bitmap value) {
...
synchronized (this) {
size += sizeOf(key, value);
Bitmap previous = map.put(key, value);
if (previous != null) {
size -= sizeOf(key, previous);
}
}
trimToSize(maxSize);
return true;
}
put方法首先調(diào)用了sizeof
方法追逮,該方法則是返回指定Bitmap的字節(jié)大小酪刀,之后size +=,總緩存量增加钮孵,之后調(diào)用trimToSize
該方法則是進(jìn)行緩存容量判斷的骂倘。
private void trimToSize(int maxSize) {
while (true) {
String key;
Bitmap value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");
}
if (size <= maxSize || map.isEmpty()) {
break;
}
Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= sizeOf(key, value);
}
}
}
如果加入后的size 緩存容量 <= maxSize 最大緩存容量,則直接break,不用進(jìn)行判定處理油猫。
如果大于的話稠茂,則直接移除最久未使用的。
大家肯定有疑問情妖,它到底怎么判斷最久未使用的睬关?沒看到相關(guān)代碼呀?
相信知道LinkedHashMap
的話可能就知道毡证。
LinkedHashMap
自身已經(jīng)實(shí)現(xiàn)了順序存儲(chǔ)电爹,默認(rèn)情況下是按照元素的添加順序存儲(chǔ),也可以啟用按照訪問順序存儲(chǔ)料睛,即最近讀取的數(shù)據(jù)放在最前面丐箩,最早讀取的數(shù)據(jù)放在最后面,然后它還有一個(gè)判斷是否刪除最老數(shù)據(jù)的方法恤煞,默認(rèn)是返回false屎勘,即不刪除數(shù)據(jù)。大家常見也就是按順序存儲(chǔ)居扒,很少忘了它還可以根據(jù)最近未使用的方法概漱。
//LinkedHashMap的一個(gè)構(gòu)造函數(shù),當(dāng)參數(shù)accessOrder為true時(shí)喜喂,即會(huì)按照訪問順序排序瓤摧,最近訪問的放在最前,最早訪問的放在后面
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
//LinkedHashMap自帶的判斷是否刪除最老的元素方法玉吁,默認(rèn)返回false照弥,即不刪除老數(shù)據(jù)
//我們要做的就是重寫這個(gè)方法,當(dāng)滿足一定條件時(shí)刪除老數(shù)據(jù)
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
回看我們前面LinkedHashMap
的創(chuàng)建
this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
再舉個(gè)使用例子
就比較明了了进副。
BaseMemoryCache
BaseMemoryCache
同樣也是實(shí)現(xiàn)了MemoryCache
方法这揣,不過(guò)它還是一個(gè)抽象類。
它是一個(gè)內(nèi)存緩存的基類影斑,實(shí)現(xiàn)了內(nèi)存緩存中常用的方法曾沈,只不過(guò)它里面提供了一個(gè)非強(qiáng)引用的Reference
作為擴(kuò)展,方便GC的回收鸥昏,避免OOM.
public abstract class BaseMemoryCache implements MemoryCache {
/** Stores not strong references to objects */
private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());
@Override
public Bitmap get(String key) {
Bitmap result = null;
Reference<Bitmap> reference = softMap.get(key);
if (reference != null) {
result = reference.get();
}
return result;
}
@Override
public boolean put(String key, Bitmap value) {
softMap.put(key, createReference(value));
return true;
}
@Override
public Bitmap remove(String key) {
Reference<Bitmap> bmpRef = softMap.remove(key);
return bmpRef == null ? null : bmpRef.get();
}
/** Creates {@linkplain Reference not strong} reference of value */
protected abstract Reference<Bitmap> createReference(Bitmap value);
}
代碼也比較簡(jiǎn)單塞俱,內(nèi)存持有一個(gè)Map<String, Reference<Bitmap>> softMap
來(lái)保存非強(qiáng)引用對(duì)象,具體的引用類型則看它實(shí)現(xiàn)的抽象方法createReference
吏垮。
WeakMemoryCache
我們看它的一個(gè)子類WeakMemoryCache
則是繼承與BaseMemory
障涯,實(shí)現(xiàn)createReference
public class WeakMemoryCache extends BaseMemoryCache {
@Override
protected Reference<Bitmap> createReference(Bitmap value) {
return new WeakReference<Bitmap>(value);
}
}
很明顯是來(lái)保存弱引用對(duì)象的。
LimitedMemoryCache
我們看它的另外一個(gè)子類LimitedMemoryCache
膳汪,但它并沒有實(shí)現(xiàn)BaseMemoryCache
里的createReference
方法唯蝶,它也是一個(gè)抽象類,在BaseMemoryCache
基礎(chǔ)上封裝了個(gè)抽象方法
protected abstract Bitmap removeNext();
用來(lái)處理當(dāng)緩存容量不足時(shí)的情況遗嗽。
public abstract class LimitedMemoryCache extends BaseMemoryCache {
...
//當(dāng)前保存的Bitmap粘我,用來(lái)統(tǒng)計(jì)緩存數(shù)
private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>());
...
@Override
public boolean put(String key, Bitmap value) {
boolean putSuccessfully = false;
// Try to add value to hard cache
int valueSize = getSize(value);
int sizeLimit = getSizeLimit();
int curCacheSize = cacheSize.get();
if (valueSize < sizeLimit) {
while (curCacheSize + valueSize > sizeLimit) {
Bitmap removedValue = removeNext();
if (hardCache.remove(removedValue)) {
curCacheSize = cacheSize.addAndGet(-getSize(removedValue));
}
}
hardCache.add(value);
cacheSize.addAndGet(valueSize);
putSuccessfully = true;
}
// Add value to soft cache
super.put(key, value);
return putSuccessfully;
}
@Override
public Bitmap remove(String key) {
Bitmap value = super.get(key);
if (value != null) {
if (hardCache.remove(value)) {
cacheSize.addAndGet(-getSize(value));
}
}
return super.remove(key);
}
...
protected abstract int getSize(Bitmap value);
protected abstract Bitmap removeNext();
}
可以看到在 LimitedMemoryCache
里面又有一個(gè)List<Bitmap>
保存的是強(qiáng)引用,而在BaseMemoryCache
里面也有個(gè)Map<String, Reference<Bitmap>> softMap
來(lái)保存Bitmap,為什么要這樣征字。
這主要是因?yàn)樵?code>BaseMemoryCache里面并沒有做緩存限制處理都弹,它只是封裝實(shí)現(xiàn)了基本的Bitmap的put,get。而當(dāng)面對(duì)緩存容量有限的情況下匙姜,則需要交給子類去處理畅厢。
我們看下這里的put方法,關(guān)鍵在
while (curCacheSize + valueSize > sizeLimit) {
Bitmap removedValue = removeNext();
if (hardCache.remove(removedValue)) {
curCacheSize = cacheSize.addAndGet(-getSize(removedValue));
}
}
當(dāng)超過(guò)容量時(shí)氮昧,調(diào)用抽象方法removeNext
由子類自行實(shí)現(xiàn)框杜,之后hardCache移除,但此時(shí)并沒有調(diào)用softMap的移除袖肥。
也就是對(duì)于List<Bitmap>
來(lái)說(shuō)咪辱,當(dāng)它的緩存容量超過(guò)的時(shí)候,它會(huì)移除第一個(gè)對(duì)象來(lái)緩解容量椎组,但是保存在Map<String, Reference<Bitmap>> softMap
里面的Bitmap并沒有被移除油狂。
如果這樣下去softMap豈不是會(huì)無(wú)限大?
這是因?yàn)樵?code>Map<String, Reference<Bitmap>> softMap里面保存的Bitmap是弱引用的存在庐杨,而在List<Bitmap>
里面保存的是強(qiáng)引用选调,當(dāng)內(nèi)存不足的時(shí)候,GC則會(huì)先清除softMap里面的對(duì)象灵份。
FIFOLimitedMemoryCache
我們看下LimitedMemoryCache
的一個(gè)子類FIFOLimitedMemoryCache
仁堪,看到FIFO也就是先進(jìn)先出了。
public class FIFOLimitedMemoryCache extends LimitedMemoryCache {
private final List<Bitmap> queue = Collections.synchronizedList(new LinkedList<Bitmap>());
...
@Override
public boolean put(String key, Bitmap value) {
if (super.put(key, value)) {
queue.add(value);
return true;
} else {
return false;
}
}
@Override
public Bitmap remove(String key) {
Bitmap value = super.get(key);
if (value != null) {
queue.remove(value);
}
return super.remove(key);
}
...
@Override
protected Bitmap removeNext() {
return queue.remove(0);
}
@Override
protected Reference<Bitmap> createReference(Bitmap value) {
return new WeakReference<Bitmap>(value);
}
}
可以看到同樣的這里也有個(gè)List<Bitmap> queue
來(lái)保存記錄填渠,而在removeNext
那里弦聂,返回的正是隊(duì)列的第一個(gè)元素,符合FIFO氛什。
LRULimitedMemoryCache
再來(lái)看一個(gè)另外一個(gè)子類LRULimitedMemoryCache
也就是最近未使用刪除莺葫。
public class LRULimitedMemoryCache extends LimitedMemoryCache {
/** Cache providing Least-Recently-Used logic */
private final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(INITIAL_CAPACITY, LOAD_FACTOR, true));
...
@Override
protected Bitmap removeNext() {
Bitmap mostLongUsedValue = null;
synchronized (lruCache) {
Iterator<Entry<String, Bitmap>> it = lruCache.entrySet().iterator();
if (it.hasNext()) {
Entry<String, Bitmap> entry = it.next();
mostLongUsedValue = entry.getValue();
it.remove();
}
}
return mostLongUsedValue;
}
@Override
protected Reference<Bitmap> createReference(Bitmap value) {
return new WeakReference<Bitmap>(value);
}
}
可以看到,這里的LRU處理則是使用LinkedHashMap
枪眉,在它的構(gòu)造方法中第三個(gè)參數(shù)為true
表示使用LRU捺檬,之后再removeNext
返回那個(gè)Bitmap。
同理其他子類也如下贸铜,就不一一列舉堡纬。
MemoryCache小結(jié)
1. 只使用的是強(qiáng)引用緩存
- LruMemoryCache(這個(gè)類就是這個(gè)開源框架默認(rèn)的內(nèi)存緩存類,緩存的是bitmap的強(qiáng)引用)
2.使用強(qiáng)引用和弱引用相結(jié)合的緩存有
UsingFreqLimitedMemoryCache(如果緩存的圖片總量超過(guò)限定值蒿秦,先刪除使用頻率最小的bitmap)
LRULimitedMemoryCache(這個(gè)也是使用的lru算法烤镐,和LruMemoryCache不同的是,他緩存的是bitmap的弱引用)
FIFOLimitedMemoryCache(先進(jìn)先出的緩存策略棍鳖,當(dāng)超過(guò)設(shè)定值炮叶,先刪除最先加入緩存的bitmap)
LargestLimitedMemoryCache(當(dāng)超過(guò)緩存限定值,先刪除最大的bitmap對(duì)象)
LimitedAgeMemoryCache(當(dāng) bitmap加入緩存中的時(shí)間超過(guò)我們?cè)O(shè)定的值,將其刪除)
3.只使用弱引用緩存
- WeakMemoryCache(這個(gè)類緩存bitmap的總大小沒有限制镜悉,唯一不足的地方就是不穩(wěn)定祟辟,緩存的圖片容易被回收掉)
二.DiskCache硬盤緩存
同樣先來(lái)看個(gè)結(jié)構(gòu)
DiskCache的設(shè)計(jì)其實(shí)和MemoryCache一樣,對(duì)于基類
DiskCache
积瞒,它同樣是一個(gè)接口
public interface DiskCache {
//返回硬盤緩存的根目錄
File getDirectory();
File get(String imageUri);
boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException;
boolean save(String imageUri, Bitmap bitmap) throws IOException;
boolean remove(String imageUri);
void close();
void clear();
}
同樣一個(gè)個(gè)看
LruDiskCache
LruDiskCache
則是直接實(shí)現(xiàn)了DiskCache
接口川尖,采用LRU算法來(lái)進(jìn)行緩存處理登下。
再理解LruDiskCache
前茫孔,先理解另一個(gè)類DiskLruCache
final class DiskLruCache implements Closeable {
static final String JOURNAL_FILE = "journal";
static final String JOURNAL_FILE_TEMP = "journal.tmp";
static final String JOURNAL_FILE_BACKUP = "journal.bkp";
static final String MAGIC = "libcore.io.DiskLruCache";
...
private final LinkedHashMap<String, Entry> lruEntries =
new LinkedHashMap<String, Entry>(0, 0.75f, true);
...
final ThreadPoolExecutor executorService =
new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
...
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize, int maxFileCount)
throws IOException {
...
}
...
public synchronized Snapshot get(String key) throws IOException {
...
}
...
private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
...
}
/** A snapshot of the values for an entry. */
public final class Snapshot implements Closeable {
private final String key;
private final long sequenceNumber;
private File[] files;
private final InputStream[] ins;
private final long[] lengths;
...
}
...
public final class Editor {
private final Entry entry;
private final boolean[] written;
private boolean hasErrors;
private boolean committed;
...
}
...
private final class Entry {
private final String key;
private final long[] lengths;
private boolean readable;
private Editor currentEditor;
private long sequenceNumber;
...
}
這個(gè)DiskLruCache
比較長(zhǎng)也比較復(fù)雜,它是LruDiskCache
的一個(gè)文件工具類被芳。這里的緩存數(shù)據(jù)存儲(chǔ)在文件系統(tǒng)上的一個(gè)目錄缰贝。
同時(shí)也注意到這里的一個(gè)成員變量
private final LinkedHashMap<String, Entry> lruEntries =new LinkedHashMap<String, Entry>(0, 0.75f, true);
可以知道這是用來(lái)處理LRU的。
同時(shí)這里的value則是Entry
畔濒,Entry
則是封裝了當(dāng)前文件的編輯情況Ediotr
以及key
剩晴。
而這里Editor
封裝了文件的寫入情況OutputStream
,Snapshot
封裝了文件的讀取情況InputStream
侵状。
回頭看回LruDiskCache
public class LruDiskCache implements DiskCache {
protected DiskLruCache cache;
private File reserveCacheDir;
protected final FileNameGenerator fileNameGenerator;
...
public LruDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator, long cacheMaxSize,
int cacheMaxFileCount) throws IOException {
...
this.reserveCacheDir = reserveCacheDir;
this.fileNameGenerator = fileNameGenerator;
initCache(cacheDir, reserveCacheDir, cacheMaxSize, cacheMaxFileCount);
}
private void initCache(File cacheDir, File reserveCacheDir, long cacheMaxSize, int cacheMaxFileCount)
...
cache = DiskLruCache.open(cacheDir, 1, 1, cacheMaxSize, cacheMaxFileCount);
...
}
@Override
public File get(String imageUri) {
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = cache.get(getKey(imageUri));
return snapshot == null ? null : snapshot.getFile(0);
}
...
}
@Override
public boolean save(String imageUri, Bitmap bitmap) throws IOException {
DiskLruCache.Editor editor = cache.edit(getKey(imageUri));
...
OutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize);
boolean savedSuccessfully = false;
try {
savedSuccessfully = bitmap.compress(compressFormat, compressQuality, os);
}
...
return savedSuccessfully;
}
首先LruDiskCache
內(nèi)部成員變量帶有DiskLruCache
還有文件的保存目錄等赞弥,在它的構(gòu)造方法中調(diào)用DiskLruCache.open
方法創(chuàng)建了DiskLruCache
對(duì)象,而在它的open方法里趣兄,則根據(jù)文件的目錄情況創(chuàng)建了對(duì)應(yīng)的文件系統(tǒng)绽左。
再看它的save方法,先調(diào)用getKey
方法將uri轉(zhuǎn)換為對(duì)應(yīng)的key艇潭,而在cache,edit中
private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
...
Entry entry = lruEntries.get(key);
if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null
|| entry.sequenceNumber != expectedSequenceNumber)) {
return null; // Snapshot is stale.
}
if (entry == null) {
entry = new Entry(key);
lruEntries.put(key, entry);
} else if (entry.currentEditor != null) {
return null; // Another edit is in progress.
}
Editor editor = new Editor(entry);
entry.currentEditor = editor;
...
return editor;
}
則是根據(jù)指定的key先判斷緩存文件中有沒有相應(yīng)的key拼窥,如果沒有則創(chuàng)建一個(gè)Entry
對(duì)象持有它,之后保存在lruEntries
之后蹋凝,創(chuàng)建一個(gè)當(dāng)前Entry
的編輯對(duì)象Editor
鲁纠,以便之后寫入到文件中。
s之后調(diào)用了
OutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize);
在editor.newOutputStream
則是根據(jù)當(dāng)前目錄和key創(chuàng)建出一個(gè)文件鳍寂,之后打開這個(gè)文件的一個(gè)輸出流情況改含,獲取到之后就進(jìn)行Bitmap的寫入。
同理迄汛,看下LruDiskCache
的get方法
@Override
public File get(String imageUri) {
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = cache.get(getKey(imageUri));
return snapshot == null ? null : snapshot.getFile(0);
}
...
}
調(diào)用了cache,get
public synchronized Snapshot get(String key) throws IOException {
捍壤。。隔心。
Entry entry = lruEntries.get(key);
...
File[] files = new File[valueCount];
InputStream[] ins = new InputStream[valueCount];
try {
File file;
for (int i = 0; i < valueCount; i++) {
file = entry.getCleanFile(i);
files[i] = file;
ins[i] = new FileInputStream(file);
}
}
...
return new Snapshot(key, entry.sequenceNumber, files, ins, entry.lengths);
}
在get方法中白群,先根據(jù)key拿到對(duì)應(yīng)的Entry
,再拿到對(duì)應(yīng)的文件打開輸入流硬霍,之后傳入到Snapshot
帜慢,
而在snapshot.getFile
中
/** Returns file with the value for {@code index}. */
public File getFile(int index) {
return files[index];
}
返回的則是對(duì)應(yīng)的文件。
BaseDiskCache
BaseDiskCache
同樣也是直接實(shí)現(xiàn)了DiskCache
方法,實(shí)現(xiàn)的方法也比較簡(jiǎn)單
public abstract class BaseDiskCache implements DiskCache {
...
protected final File cacheDir;
protected final File reserveCacheDir;
protected final FileNameGenerator fileNameGenerator;
public BaseDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) {
...
this.cacheDir = cacheDir;
this.reserveCacheDir = reserveCacheDir;
this.fileNameGenerator = fileNameGenerator;
}
@Override
public boolean save(String imageUri, Bitmap bitmap) throws IOException {
File imageFile = getFile(imageUri);
File tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX);
OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize);
boolean savedSuccessfully = false;
try {
savedSuccessfully = bitmap.compress(compressFormat, compressQuality, os);
} finally {
IoUtils.closeSilently(os);
if (savedSuccessfully && !tmpFile.renameTo(imageFile)) {
savedSuccessfully = false;
}
if (!savedSuccessfully) {
tmpFile.delete();
}
}
bitmap.recycle();
return savedSuccessfully;
}
@Override
public File get(String imageUri) {
return getFile(imageUri);
}
protected File getFile(String imageUri) {
String fileName = fileNameGenerator.generate(imageUri);
File dir = cacheDir;
if (!cacheDir.exists() && !cacheDir.mkdirs()) {
if (reserveCacheDir != null && (reserveCacheDir.exists() || reserveCacheDir.mkdirs())) {
dir = reserveCacheDir;
}
}
return new File(dir, fileName);
}
比較簡(jiǎn)單粱玲,根據(jù)對(duì)應(yīng)的文件去打開獲取躬柬。它的兩個(gè)子類LimitedAgeDiskCache
和UnlimitedDiskCache
也都不一一擴(kuò)展開了。