两种缓存
- 内存缓存
a.活动资源 (Active Resources):正在使用的图片。
b.内存缓存 (Memory cache):内存缓存中的图片。 - 磁盘缓存
a.资源类型(Resource):磁盘缓存中转换过后的图片。
b.数据来源 (Data):磁盘缓存中的原始图片。
缓存策略
第一次从网络上加载图片后,将它缓存到设备磁盘和内存中,其他地方或者下次使用这张图片的时候就不从网络上请求了。下次需要加载这张图片时,首先从内存缓存中找,如果没有就去磁盘缓存中查找,都没有才从网络上加载。
缓存Key
缓存功能必然要有一个唯一的缓存Key用来存储和查找对应的缓存数据。看一下Engine类的load()方法。
/**
* 1.Engine 类
*/
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//构建缓存Key
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
// Avoid calling back while holding the engine lock, doing so makes it easier for callers to
// deadlock.
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
我们再看EngineKeyFactory类。
/**
* 2.EngineKeyFactory
* */
class EngineKeyFactory {
@SuppressWarnings("rawtypes")
EngineKey buildKey(
Object model,
Key signature,
int width,
int height,
Map<Class<?>, Transformation<?>> transformations,
Class<?> resourceClass,
Class<?> transcodeClass,
Options options) {
//返回一个新的缓存Key
return new EngineKey(
model, signature, width, height, transformations, resourceClass, transcodeClass, options);
}
}
我们再看EngineKey类,通过重写equals()与hashCode()方法来保证缓存Key的唯一性。
class EngineKey implements Key {
private final Object model;
private final int width;
private final int height;
private final Class<?> resourceClass;
private final Class<?> transcodeClass;
private final Key signature;
private final Map<Class<?>, Transformation<?>> transformations;
private final Options options;
private int hashCode;
EngineKey(
Object model,
Key signature,
int width,
int height,
Map<Class<?>, Transformation<?>> transformations,
Class<?> resourceClass,
Class<?> transcodeClass,
Options options) {
this.model = Preconditions.checkNotNull(model);
this.signature = Preconditions.checkNotNull(signature, "Signature must not be null");
this.width = width;
this.height = height;
this.transformations = Preconditions.checkNotNull(transformations);
this.resourceClass =
Preconditions.checkNotNull(resourceClass, "Resource class must not be null");
this.transcodeClass =
Preconditions.checkNotNull(transcodeClass, "Transcode class must not be null");
this.options = Preconditions.checkNotNull(options);
}
@Override
public boolean equals(Object o) {
if (o instanceof EngineKey) {
EngineKey other = (EngineKey) o;
return model.equals(other.model)
&& signature.equals(other.signature)
&& height == other.height
&& width == other.width
&& transformations.equals(other.transformations)
&& resourceClass.equals(other.resourceClass)
&& transcodeClass.equals(other.transcodeClass)
&& options.equals(other.options);
}
return false;
}
@Override
public int hashCode() {
if (hashCode == 0) {
hashCode = model.hashCode();
hashCode = 31 * hashCode + signature.hashCode();
hashCode = 31 * hashCode + width;
hashCode = 31 * hashCode + height;
hashCode = 31 * hashCode + transformations.hashCode();
hashCode = 31 * hashCode + resourceClass.hashCode();
hashCode = 31 * hashCode + transcodeClass.hashCode();
hashCode = 31 * hashCode + options.hashCode();
}
return hashCode;
}
@Override
public String toString() {...}
@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
throw new UnsupportedOperationException();
}
内存缓存
在内存缓存中,我们需要记住两个内容,一个叫活动资源,一个叫内存缓存。我们从load()方法开始讲解。
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
//根据缓存Key从内存中获取缓存
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
// Avoid calling back while holding the engine lock, doing so makes it easier for callers to
// deadlock.
//加载缓存后回调
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
再看loadFromMemory方法。
@Nullable
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
//若不可以内存缓存,直接返回null
if (!isMemoryCacheable) {
return null;
}
//从(活动资源)ActiveResources中加载缓存数据。
EngineResource<?> active = loadFromActiveResources(key);
//如果有活动资源,则直接返回
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return active;
}
//若活动资源没有,则从内存缓存中加载缓存数据。
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
}
return null;
}
再看loadFromActiveResources方法。
@Nullable
private EngineResource<?> loadFromActiveResources(Key key) {
//根据Key去获取活动资源
EngineResource<?> active = activeResources.get(key);
//若资源不为null,执行acquire()方法
if (active != null) {
active.acquire();
}
//返回活动资源
return active;
}
再看ActiveResources类的get()方法。
@Nullable
synchronized EngineResource<?> get(Key key) {
//弱引用的haspMap,获取ResourceWeakReference
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
return null;
}
//从弱引用中获取活动资源,得到EngineResource
EngineResource<?> active = activeRef.get();
//若资源为空,则回收activeRef
if (active == null) {
cleanupActiveReference(activeRef);
}
return active;
}
再看EngineResource类的acquire()方法。
synchronized void acquire() {
if (isRecycled) {
throw new IllegalStateException("Cannot acquire a recycled resource");
}
//计数加1,用来记录图片被引用的次数
++acquired;
}
这个时候如果活动资源有数据,就已经取到了缓存。若此时活动资源没有数据,则需要去内存缓存中去取。即从loadFromCache方法开始。我们再看一下这个方法。
private EngineResource<?> loadFromCache(Key key) {
//获取内存缓存
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
//计数+1,用来记录图片被引用的次数。
cached.acquire();
//将内存中获取的缓存数据缓存到弱引用的HashMap中,这个时候就是将内存缓存中的缓存放到活动资源中。
activeResources.activate(key, cached);
}
return cached;
}
再看一下getEngineResourceFromCache()方法。
private EngineResource<?> getEngineResourceFromCache(Key key) {
//remove()操作就是移除缓存的同时获取该缓存(获取内存缓存)
Resource<?> cached = cache.remove(key);
final EngineResource<?> result;
if (cached == null) {
result = null;
} else if (cached instanceof EngineResource) {
result = (EngineResource<?>) cached;
} else {
result =
new EngineResource<>(
cached, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
}
return result;
}
从上面的方法可以知道活动资源里的缓存怎么来的,就是内存缓存中取了缓存资源后存到了活动资源。那么内存缓存中的缓存是怎么来的?刚才我们提到活动资源在获取的时候有个+1的计数操作,看一下活动资源释放的时候是怎么样的呢?看下EngineResource类的release()方法。
void release() {
boolean release = false;
synchronized (this) {
//如果计数值<= 0,则证明这个资源没有地方调用
if (acquired <= 0) {
throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
}
//释放一次,计数减-1,若==0,则证明没有地方用了,需要回收了
if (--acquired == 0) {
release = true;
}
}
//如果活动资源需要释放了,则有个监听方法
if (release) {
listener.onResourceReleased(key, this);
}
}
再看Engine类中的onResourceReleased()方法。
@Override
public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
//根据cacheKey活动资源的HashMap中删除
activeResources.deactivate(cacheKey);
//若可以缓存,则缓存到内存缓存中,
if (resource.isMemoryCacheable()) {
//MemoryCache cache
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource, /*forceNextFrame=*/ false);
}
}
从这可以看出来,内存缓存的数据是从活动资源释放的时候存储起来的。
总结:
- 活动资源的流程:从活动资源(hashMap)中找,如有则计数+1,释放资源时计数-1,若计数为0则缓存到内存缓存中,同时在活动资源中删除。
- 内存缓存的流程:根据Key从内存缓存中删除的同时找出来,然后将内存缓存中获取的缓存资源缓存到活动资源的弱引用的HashMap中。
问题
- 活动资源的内容哪里来的?
答案:首次:从网络请求中返回的数据。 - 为啥要用一个弱引用的HashMap?
答案:(1)提高访问效率。HashMap的访问速度是要比LinkedHashMap快;(2)防止内存泄漏。
- 强引用:直接的对象引用。
- 软引用:当一个对象只有软引用存在时,系统内存不足时此对象会被gc回收。
- 弱引用:当一个对象只有弱引用存在时, 此对象会随时被gc回收。
磁盘缓存
在磁盘缓存中,我们需要记住两个名词,叫资源类型和数据来源。
磁盘缓存设置
- ALL:既缓存原始图片,也缓存转换过后的图片。
- NONE:不缓存任何内容。
- DATA:只缓存原始图片。
- RESOURCE:只缓存转换过后的图片。
- AUTOMATIC:默认策略,它会尝试对本地和远程图片使用最佳的策略。如果是远程图片,则只缓存原始图片;如果是本地图片,那么只缓存转换过后的图片。
缓存算法
LRU(Least Recently Used),即最近最少使用算法。核心思想是当缓存满时,会优先淘汰那些最近最少使用的缓存对象。采用 LRU算法的缓存有两种:LruCache和DiskLruCache。内部算法原理是采用一个LinkedHashMap(有序存储key-value)以强引用的方式存储外界的缓存对象,其提供了get()和put()方法来完成缓存的获取和添加的操作。当缓存满时,会移除较早使用的缓存对象,然后再添加新的缓存对象。
资源类型(Resource)
如何获取缓存,先看DecodeJob这个类。
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//1.获取资源状态
stage = getNextStage(Stage.INITIALIZE);
//2.根据资源状态获取资源执行器
currentGenerator = getNextGenerator();
//3.执行
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
//获取资源状态Stage
//根据当前用户设置的缓存机制可以得到diskCacheStrategy.decodeCachedResource()和diskCacheStrategy.decodeCachedData()的值,在DiskCacheStrategy类中可以看到具体返回值。
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE
: getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE
: getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// Skip loading from source if the user opted to only retrieve the resource from cache.
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
//根据Stage获取资源执行器
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
//当前的执行器执行,即currentGenerator.startNext()方法
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
//走下一个Stage和执行器
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
}
若配置的是Resource,则执行器是ResourceCacheGenerator,然后看一下这个执行器的startNext()的具体内容。
@Override
public boolean startNext() {
...
//构建缓存Key
currentKey =
new ResourceCacheKey( // NOPMD AvoidInstantiatingObjectsInLoops
helper.getArrayPool(),
sourceId,
helper.getSignature(),
helper.getWidth(),
helper.getHeight(),
transformation,
resourceClass,
helper.getOptions());
//根据缓存Key去获取缓存文件,获取的是缓存文件
cacheFile = helper.getDiskCache().get(currentKey);
if (cacheFile != null) {
sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
//对缓存文件进行处理
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
ByteBufferFileLoader类中的loadData()方法。
@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
//将缓存文件转换成ByteBuffer
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to obtain ByteBuffer for file", e);
}
//失败返回
callback.onLoadFailed(e);
return;
}
//成功则将ByteBuffer返回,最终回调到DecodeJob的onDataFetcherReady()方法中
callback.onDataReady(result);
}
到此,获取资源类型的缓存结束。然后看一下如何存储的。刚才说到DecodeJob类,看一下里面的notifyEncodeAndRelease()方法。
//解码完成了通知下去的步骤
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
if (resource instanceof Initializable) {
((Initializable) resource).initialize();
}
Resource<R> result = resource;
LockedResource<R> lockedResource = null;
if (deferredEncodeManager.hasResourceToEncode()) {
lockedResource = LockedResource.obtain(resource);
result = lockedResource;
}
notifyComplete(result, dataSource);
stage = Stage.ENCODE;
try {
if (deferredEncodeManager.hasResourceToEncode()) {
//将资源缓存到磁盘
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
onEncodeComplete();
}
void encode(DiskCacheProvider diskCacheProvider, Options options) {
GlideTrace.beginSection("DecodeJob.encode");
try {
//存储缓存(转换格式后的图片)
diskCacheProvider
.getDiskCache()
.put(key, new DataCacheWriter<>(encoder, toEncode, options));
} finally {
toEncode.unlock();
GlideTrace.endSection();
}
}
总结
- 资源类型的获取流程:先初始化资源状态为INITIALIZE,然后根据设置的磁盘缓存策略得到资源状态Stage,根据资源状态Stage获取到资源执行器,再执行。执行执行器,先构建缓存Key,根据缓存Key去寻找缓存文件,若有则处理缓存文件为ByteBuffer,返回给DecodeJob进行展示等操作。
- 资源类型的存储流程:第一次加载的时候在SourceGenerator的startNext()方法中请求到数据,然后解码完成,最后再存储缓存。
数据来源(Data)
如何获取缓存,先看DecodeJob这个类。
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//1.获取资源状态
stage = getNextStage(Stage.INITIALIZE);
//2.根据资源状态获取资源执行器
currentGenerator = getNextGenerator();
//3.执行
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
//获取资源状态Stage
//根据当前用户设置的缓存机制可以得到diskCacheStrategy.decodeCachedResource()和diskCacheStrategy.decodeCachedData()的值,在DiskCacheStrategy类中可以看到具体返回值。
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE
: getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE
: getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// Skip loading from source if the user opted to only retrieve the resource from cache.
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
//根据Stage获取资源执行器
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
//当前的执行器执行,即currentGenerator.startNext()方法
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
//走下一个Stage和执行器
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
}
若配置的是Data,则执行器是DataCacheGenerator,然后看一下这个执行器的startNext()的具体内容。
@Override
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
Key sourceId = cacheKeys.get(sourceIdIndex);
// PMD.AvoidInstantiatingObjectsInLoops The loop iterates a limited number of times
// and the actions it performs are much more expensive than a single allocation.
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
//构建缓存Key
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
//根据缓存Key去获取缓存文件
cacheFile = helper.getDiskCache().get(originalKey);
if (cacheFile != null) {
this.sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
//加工缓存文件
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
ByteBufferFileLoader类中的loadData()方法。
@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
//将缓存文件转换成ByteBuffer
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to obtain ByteBuffer for file", e);
}
//失败返回
callback.onLoadFailed(e);
return;
}
//成功则将ByteBuffer返回,最终回调到DecodeJob的onDataFetcherReady()方法中
callback.onDataReady(result);
}
到此,获取数据来源的缓存结束。然后看一下如何存储的。看SourceGenerator类中的onDataReadyInternal()方法,这个方法是请求网络得到数据的时候。
@Synthetic
void onDataReadyInternal(LoadData<?> loadData, Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
//对即将需要缓存的数据进行赋值
dataToCache = data;
// We might be being called back on someone else's thread. Before doing anything, we should
// reschedule to get back onto Glide's thread.
//回调
cb.reschedule();
} else {
cb.onDataFetcherReady(
loadData.sourceKey,
data,
loadData.fetcher,
loadData.fetcher.getDataSource(),
originalKey);
}
}
然后看一下EngineJob的reschedule()方法。
@Override
public void reschedule(DecodeJob<?> job) {
// Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself
// up.
//用线程池执行了DecodeJob,然后回到了SourceGenerator的startNext()方法
getActiveSourceExecutor().execute(job);
}
看一下SourceGenerator的startNext()方法
@Override
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
//存储缓存数据
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
startNextLoad(loadData);
}
}
return started;
}
//存储数据方法
private void cacheData(Object dataToCache) {
long startTime = LogTime.getLogTime();
try {
Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
DataCacheWriter<Object> writer =
new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
//构建缓存Key
originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
//存储缓存文件
helper.getDiskCache().put(originalKey, writer);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(
TAG,
"Finished encoding source to cache"
+ ", key: "
+ originalKey
+ ", data: "
+ dataToCache
+ ", encoder: "
+ encoder
+ ", duration: "
+ LogTime.getElapsedMillis(startTime));
}
} finally {
loadData.fetcher.cleanup();
}
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
}
总结
- 原始数据的获取流程:先初始化资源状态为INITIALIZE,然后根据设置的磁盘缓存策略得到资源状态Stage,根据资源状态Stage获取到资源执行器,再执行。执行执行器,先构建缓存Key,根据缓存Key去寻找缓存文件,若有则处理缓存文件为ByteBuffer,返回给DecodeJob进行展示等操作。
- 原始数据的存储流程:网络请求结束得到数据时,在SourceGenerator的startNext()方法中构建原始Key,存储原始图片。