分為內(nèi)存緩存以及硬盤緩存孤里,內(nèi)存緩存又分為lruresourchcache和弱引用緩存燕酷。
緩存的key粮揉,參數(shù)很多膊畴,通過(guò)equals和hashcode算法來(lái)判斷是否是同一個(gè)key.
先是從loadFromCache里面讀取织中,內(nèi)部代碼先是從cache里面移除锥涕,添加到弱引用的資源里面。LinkedHashMap, LruCache 實(shí)現(xiàn)了MemoryCache抠璃。如果cache里面沒(méi)有這條數(shù)據(jù)站楚,從loadFromActiveResources里面讀取。還是沒(méi)有數(shù)據(jù)搏嗡,從網(wǎng)絡(luò)獲取窿春。
對(duì)于內(nèi)存緩存,正在使用的圖片使用弱引用緩存采盒,不在使用的圖片使用lrucache來(lái)進(jìn)行緩存旧乞。
為啥使用弱引用緩存:防止lrucache將正在使用的圖片緩存清除掉。
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
final String id = fetcher.getId();
//生成key
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
//內(nèi)存緩存讀取保存的數(shù)據(jù)
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
//內(nèi)存的弱引用當(dāng)中讀取數(shù)據(jù)
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
//網(wǎng)絡(luò)獲取數(shù)據(jù)
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
//從緩存讀取數(shù)據(jù)
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
//添加數(shù)據(jù)到弱引用當(dāng)中
activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
}
return cached;
}
@SuppressWarnings("unchecked")
private EngineResource<?> getEngineResourceFromCache(Key key) {
Resource<?> cached = cache.remove(key);
final EngineResource result;
if (cached == null) {
result = null;
} else if (cached instanceof EngineResource) {
// Save an object allocation if we've cached an EngineResource (the typical case).
result = (EngineResource) cached;
} else {
result = new EngineResource(cached, true /*isCacheable*/);
}
return result;
}
handleResulteOnMainThread()方法中磅氨,數(shù)據(jù)寫入內(nèi)存尺栖,先是寫入到弱引用緩存當(dāng)中,
數(shù)據(jù)寫入內(nèi)存:根據(jù)一個(gè)int數(shù)據(jù)烦租,作為這張圖片當(dāng)前被使用的次數(shù)延赌,當(dāng)這個(gè)計(jì)數(shù)器>0的時(shí)候,是在弱引用里面叉橱,當(dāng)這個(gè)計(jì)數(shù)器==0的時(shí)候挫以,調(diào)用一個(gè)回調(diào),將數(shù)據(jù)從弱引用移除掉窃祝,添加到lrucache里面掐松。通過(guò)這個(gè)計(jì)數(shù)器來(lái)判斷是寫入lrusource里面還是弱引用里面。
@SuppressWarnings("unchecked")
@Override
public void onEngineJobComplete(Key key, EngineResource<?> resource) {
Util.assertMainThread();
// A null resource indicates that the load failed, usually due to an exception.
if (resource != null) {
resource.setResourceListener(key, this);
if (resource.isCacheable()) {
activeResources.put(key, new ResourceWeakReference(key, resource, getReferenceQueue()));
}
}
// TODO: should this check that the engine job is still current?
jobs.remove(key);
}
@Override
public void onResourceReleased(Key cacheKey, EngineResource resource) {
Util.assertMainThread();
activeResources.remove(cacheKey);
if (resource.isCacheable()) {
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
}
}
網(wǎng)絡(luò)獲取的時(shí)候,先是從硬盤讀取數(shù)據(jù)大磺,硬盤里面先是從result里面讀取抡句,如果沒(méi)有,再?gòu)膕ource里面讀雀芾ⅰ待榔!
class EngineRunnable implements Runnable, Prioritized {
private static final String TAG = "EngineRunnable";
private final Priority priority;
private final EngineRunnableManager manager;
private final DecodeJob<?, ?, ?> decodeJob;
private Stage stage;
private volatile boolean isCancelled;
public EngineRunnable(EngineRunnableManager manager, DecodeJob<?, ?, ?> decodeJob, Priority priority) {
this.manager = manager;
this.decodeJob = decodeJob;
this.stage = Stage.CACHE;
this.priority = priority;
}
public void cancel() {
isCancelled = true;
decodeJob.cancel();
}
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
resource = decode();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
exception = e;
}
if (isCancelled) {
if (resource != null) {
resource.recycle();
}
return;
}
if (resource == null) {
onLoadFailed(exception);
} else {
onLoadComplete(resource);
}
}
private boolean isDecodingFromCache() {
return stage == Stage.CACHE;
}
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
}
private void onLoadFailed(Exception e) {
if (isDecodingFromCache()) {
stage = Stage.SOURCE;
manager.submitForSource(this);
} else {
manager.onException(e);
}
}
private Resource<?> decode() throws Exception {
if (isDecodingFromCache()) {
return decodeFromCache();
} else {
return decodeFromSource();
}
}
//硬盤讀取數(shù)據(jù)
private Resource<?> decodeFromCache() throws Exception {
Resource<?> result = null;
try {
result = decodeJob.decodeResultFromCache();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Exception decoding result from cache: " + e);
}
}
if (result == null) {
result = decodeJob.decodeSourceFromCache();
}
return result;
}
//網(wǎng)絡(luò)讀取數(shù)據(jù)
private Resource<?> decodeFromSource() throws Exception {
return decodeJob.decodeFromSource();
}
@Override
public int getPriority() {
return priority.ordinal();
}
private enum Stage {
/** Attempting to decode resource from cache. */
CACHE,
/** Attempting to decode resource from source data. */
SOURCE
}
interface EngineRunnableManager extends ResourceCallback {
void submitForSource(EngineRunnable runnable);
}
}
硬盤讀取數(shù)據(jù),會(huì)分為DiskCacheStrategy.SOURCE和DiskCacheStrategy.RESULT兩種殴蹄。在DecodeJob類當(dāng)中究抓。
public Resource<Z> decodeResultFromCache() throws Exception {
if (!diskCacheStrategy.cacheResult()) {
return null;
}
long startTime = LogTime.getLogTime();
Resource<T> transformed = loadFromCache(resultKey);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded transformed from cache", startTime);
}
startTime = LogTime.getLogTime();
Resource<Z> result = transcode(transformed);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transcoded transformed from cache", startTime);
}
return result;
}
public Resource<Z> decodeSourceFromCache() throws Exception {
if (!diskCacheStrategy.cacheSource()) {
return null;
}
long startTime = LogTime.getLogTime();
Resource<T> decoded = loadFromCache(resultKey.getOriginalKey());
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded source from cache", startTime);
}
return transformEncodeAndTranscode(decoded);
}
private Resource<T> loadFromCache(Key key) throws IOException {
File cacheFile = diskCacheProvider.getDiskCache().get(key);
if (cacheFile == null) {
return null;
}
Resource<T> result = null;
try {
result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
} finally {
if (result == null) {
diskCacheProvider.getDiskCache().delete(key);
}
}
return result;
}
禁止Glide對(duì)圖片進(jìn)行硬盤緩存
Glide.with(this).load(url).diskCacheStrategy(DiskCacheStrategy.NONE).into(imageView);
硬盤的寫入:
private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
long startTime = LogTime.getLogTime();
SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
startTime = LogTime.getLogTime();
Resource<T> result = loadFromCache(resultKey.getOriginalKey());
return result;
}