Glide源码分析:缓存机制

前言

Glide作为一个强大的图片加载框架,必然有着一套完整且优秀的缓存机制。本文将基于Glide-4.9.0版本,对Glide的缓存机制进行源码分析。

缓存相关的类

下面先介绍一下Glide缓存涉及到的一些类:

ActiveResources

ActiveResources是第一级缓存,表示当前正在活动的资源。当资源加载成功,或者通过其他缓存获得资源后都会将其添加到ActiveResources中。当资源被gc后,就会将其移除出ActiveResources。

ActiveResources通过Map来存储数据,数据保存在WeakReference中

1
2
//ResourceWeakReference继承于WeakReference<EngineResource<?>>
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();

此外,还有一个引用队列

1
private final ReferenceQueue<EngineResource<?>> resourceReferenceQueue = new ReferenceQueue<>();

当一个弱引用对象被gc掉之后,其对应的Reference对象会加入到引用队列中。从引用队列获取到被gc掉的弱引用对象后,就可以将该对象从ActiveResources中删除。

MemoryCache

MemoryCache(内存缓存)是第二级缓存,如果ActiveResources没有获取到资源就从这里获取。

它的实现类是LruResourceCache,继承于LruCahce。主要的实现在LruCache中,LruCache使用LRU算法进行缓存。它的内部使用LinkedHashMap存储数据,LinkedHashMap内部可以设置为按照访问顺序进行排序,最近最少访问的在前面,这很适合LRU算法,在清除缓存的时候,只要从前面的元素开始删除,一直删除到满足容量即可。

LruCache

看下LruCache中存取数据的几个方法:

get方法获取指定数据

1
2
3
4
 public synchronized Y get(@NonNull T key) {
//获取缓存数据
return cache.get(key);
}

remove方法删除指定数据

1
2
3
4
5
6
7
8
9
 public synchronized Y remove(@NonNull T key) {
//从缓存中删除指定数据
final Y value = cache.remove(key);
//如果删除成功,就更新当前缓存容量,并返回删除数据
if (value != null) {
currentSize -= getSize(value);
}
return value;
}

put方法添加缓存数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 public synchronized Y put(@NonNull T key, @Nullable Y item) {
//获取资源的大小
final int itemSize = getSize(item);
//资源大小超出容量限制,不缓存该资源,并回调该资源的移除
if (itemSize >= maxSize) {
onItemEvicted(key, item);
return null;
}
//如果资源不为空,更新当前缓存容量
if (item != null) {
currentSize += itemSize;
}
//将当前资源添加进缓存中
@Nullable final Y old = cache.put(key, item);
//如果该key之前有其他资源,更新当前缓存容量,并回调该资源的移除
if (old != null) {
currentSize -= getSize(old);

if (!old.equals(item)) {
onItemEvicted(key, old);
}
}
//从缓存中删除最近最少使用的数据,直到满足指定容量
evict();

return old;
}

这几个方法还是比较好理解的,代码中都有注释。

MemorySizeCalculator

MemoryCache在创建Glide实例时初始化,内存缓存的初始化容量从MemorySizeCalculator中获得,代码如下:

1
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());

getMemoryCacheSize方法如下:

1
2
3
public int getMemoryCacheSize() {
return memoryCacheSize;
}

其中memoryCacheSize在MemorySizeCalculator初始化时指定,MemorySizeCalculator的初始化也是发生在Glide实例创建时:

1
2
3
if (memorySizeCalculator == null) {
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}

这里采用了Builder模式,在其内部类Builder的build方法中调用了MemorySizeCalculator的构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 MemorySizeCalculator(MemorySizeCalculator.Builder builder) {

//ArrayPool的容量默认为4MB,低内存设备为2MB
arrayPoolSize =
isLowMemoryDevice(builder.activityManager)
? builder.arrayPoolSizeBytes / LOW_MEMORY_BYTE_ARRAY_POOL_DIVISOR
: builder.arrayPoolSizeBytes;
//最大容量为:当前进程可用内存 * 0.4;对低内存设备,为当前进程可以内存 * 0.33
int maxSize =
getMaxSize(
builder.activityManager, builder.maxSizeMultiplier, builder.lowMemoryMaxSizeMultiplier);

//计算一张大小为屏幕大小,格式为ARGB_8888的图片占用的内存大小(包括BitmapPool和MemoryCache)
int widthPixels = builder.screenDimensions.getWidthPixels();
int heightPixels = builder.screenDimensions.getHeightPixels();
int screenSize = widthPixels * heightPixels * BYTES_PER_ARGB_8888_PIXEL;
int targetBitmapPoolSize = Math.round(screenSize * builder.bitmapPoolScreens);
int targetMemoryCacheSize = Math.round(screenSize * builder.memoryCacheScreens);

//去掉ArrayPool占用的内存后,剩余的内存大小
int availableSize = maxSize - arrayPoolSize;

//BitmapPool和MemoryCache的内存相加不超过可用内存大小
if (targetMemoryCacheSize + targetBitmapPoolSize <= availableSize) {
memoryCacheSize = targetMemoryCacheSize;
bitmapPoolSize = targetBitmapPoolSize;
}
//超出限制的话,两者按照比例平分可用大小
else {
float part = availableSize / (builder.bitmapPoolScreens + builder.memoryCacheScreens);
memoryCacheSize = Math.round(part * builder.memoryCacheScreens);
bitmapPoolSize = Math.round(part * builder.bitmapPoolScreens);
}

}

可以看到,构造方法中指定了 BitmapPool 和 MemoryCache 可用的内存大小。 BitmapPool 是用来复用 Bitmap,从而避免重复创建 Bitmap 而带来的内存浪费。

小结一下计算BitmapPool和MemoryCache可用内存的步骤:

  1. 设置ArrayPool的容量,默认为4MB,低内存设备为2MB(安卓版本低于4.4默认为低内存,其它版本由系统判断)
  2. 设置最大容量,默认为当前进程可用内存 0.4,低内存设备 0.3
  3. 设置可用内存容量为最大容量减去ArrayPool的容量
  4. 计算一张大小为屏幕大小,格式为ARGB_8888的图片占用的内存大小(包括BitmapPool和MemoryCache),如果两者内存相加不超过可用容量,那么计算得出的内存大小即为各自的可用内存。如果相加后超出限制的话,两者按照比例平分可用内存。

过程分析

在执行Request的时候,会调用SingleRequest的onSizeReady方法进行加载数据:

SingleRequest#onSizeReady

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 @Override
public synchronized void onSizeReady(int width, int height) {

if (status != Status.WAITING_FOR_SIZE) {
return;
}
//Request的状态变为RUNNING
status = Status.RUNNING;

//...

//加载资源
loadStatus =
engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);

//...

}

在真正加载资源前,将Request的状态变为RUNNING。之后调用Engine的load方法真正加载资源:

Engine#load

该方法首先生成缓存key,该key是一个EngineKey对象,由传入的多个参数生成。

1
2
3
   //生成缓存key(该key是一个EngineKey对象)
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);

ActiveResources缓存

接着根据该缓存key获取缓存资源,首先从ActiveResources中获取缓存:

1
2
3
4
5
6
7
8
//从ActiveResources(弱引用)中获取缓存
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
//获取到缓存资源,回调onResourceReady方法
cb.onResourceReady(active, DataSource.MEMORY_CACHE);

return null;
}

loadFromActiveResources方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
 private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
//获取缓存资源
EngineResource<?> active = activeResources.get(key);
//如果获取到缓存资源,就更新资源获取次数
if (active != null) {
active.acquire();
}

return active;
}

内存缓存

如果ActiveResources中获取不到,就从内存中获取缓存,如果成功获取到缓存,就将缓存从内存中删除并将添加到ActiceResources中:

1
2
3
4
5
6
7
8
//如果ActiveResources中获取不到,就从内存中获取缓存
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
//获取到缓存资源,回调onResourceReady方法
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);

return null;
}

loadFromCache方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}

//从内存中获取缓存,获取到缓存后,将缓存从内存中删除
EngineResource<?> cached = getEngineResourceFromCache(key);
//如果获取到缓存
if (cached != null) {
//更新资源的获取次数
cached.acquire();
//将获取到的资源添加到ActiceResources中
activeResources.activate(key, cached);
}

return cached;
}

磁盘缓存

如果在内存中获取不到缓存,就要执行以下步骤

1
2
3
4
5
6
7
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {

current.addCallback(cb, callbackExecutor);

return new LoadStatus(cb, current);
}

其中jobs为Jobs对象,看Jobs的get方法:

1
2
3
EngineJob<?> get(Key key, boolean onlyRetrieveFromCache) {
return getJobMap(onlyRetrieveFromCache).get(key);
}

继续看getJobMap方法:

1
2
3
private Map<Key, EngineJob<?>> getJobMap(boolean onlyRetrieveFromCache) {
return onlyRetrieveFromCache ? onlyCacheJobs : jobs;
}

其中:onlyCacheJobs和jobs的定义如下:

1
2
private final Map<Key, EngineJob<?>> jobs = new HashMap<>();
private final Map<Key, EngineJob<?>> onlyCacheJobs = new HashMap<>();

最终,返回一个EngineJob对象,并且第一次加载的话返回null,继续执行下面语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);

DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);

jobs.put(key, engineJob);

engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob);

return new LoadStatus(cb, engineJob);

先创建EngineJob和DecodeJob,然后将EngineJob加到Jobs的Map中保存起来。EngineJob主要用于执行DecodeJob以及管理加载完成的回调,DecodeJob是一个Runnable,负责从磁盘或网络中加载数据。

EngineJob通过start方法执行DecodeJob

1
2
3
4
5
6
7
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}

可以看到,DecodeJob是在线程池里执行的,DecodeJob的run中又调用了runWrapped方法:

DecodeJob#runWrapped

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void runWrapped() {
switch (runReason) {
//第一次调用runWrapped时,为INITIALIZE状态
case INITIALIZE:
//获取下一状态
stage = getNextStage(Stage.INITIALIZE);
//根据状态获得对应的DataFetcherGenerator
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}

其中状态的变化如下:

DecodeJob#getNextStage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
//如果要从RESOURCE_CACHE获取缓存,下一状态为RESOURCE_CACHE,否则跳过RESOURCE_CACHE
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
//如果要从DATA_CACHE获取缓存,下一状态为DATA_CACHE,否则跳过DATA_CACHE
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
//如果用户仅从缓存中获取资源,就跳过从数据源获取数据的步骤
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}

注意区分两种状态:在runWrapped方法中的状态为RunReason,在getNextStage方法中的状态为Stage。

在获取下一State时,调用DiskCacheStrategy对象的decodeCachedResource方法,用户可以通过设置相应的DiskCacheStrategy对象来配置Glide的硬盘缓存,用法如下:

1
2
3
4
5
Glide.with(MainActivity.this)
.applyDefaultRequestOptions(new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.NONE))
.load(url)
.into(mPicIv);

调用diskCacheStrategy方法并传入DiskCacheStrategy.NONE后,就可以禁止掉硬盘缓存。硬盘缓存策略共有以下几种:

  • DiskCacheStrategy.NONE:不缓存任何内容
  • DiskCacheStrategy.DATA:只缓存原始图片
  • DiskCacheStrategy.RESOURCE:只缓存转换后的图片
  • DiskCacheStrategy.ALL:既缓存原始图片,也缓存转换后的图片
  • DiskCacheStrategy.AUTOMATIC:让Glide根据图片资源智能选择策略(默认)

回到runWrapped方法,在确定了state后,根据state获得对应的DataFetcherGenerator,看getNextGenerator方法:

DecodeJob#getNextGenerator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
}
}

获得相应DataFetcherGenerator后,执行runGenerators方法:

DecodeJob#runGenerators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private void runGenerators() {

boolean isStarted = false;
//如果在执行DataFetcherGenerator的startNext方法加载到缓存数据后,就不再进入循环体
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
//上一状态没有获取到缓存,获取下一状态和与该状态对应的DataFetcherGenerator
stage = getNextStage(stage);
currentGenerator = getNextGenerator();

//RunReason变为SWITCH_TO_SOURCE_SERVICE状态,然后重新执行DecodeJob(即又执行runWrapped方法,
//不过此时可能是在另一个子线程中执行)
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}

// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}

}

首先会执行对应Generator的startNext方法,假如state为RESOURCE_CACHE(磁盘缓存策略为DiskCacheStrategy.RESOURCE或DiskCacheStrategy.ALL),则执行ResourceCacheGenerator的startNext方法:

ResourceCacheGenerator#startNext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 public boolean startNext() {
//...

while (modelLoaders == null || !hasNextModelLoader()) {
//...

//得到缓存key
currentKey =
new ResourceCacheKey(// NOPMD AvoidInstantiatingObjectsInLoops
helper.getArrayPool(),
sourceId,
helper.getSignature(),
helper.getWidth(),
helper.getHeight(),
transformation,
resourceClass,
helper.getOptions());

//helper.getDiskCache()最终调用的是Engine.LazyDiskCacheProvider的getDiskCache方法
//该方法返回一个DiskCache接口对象,其实现类是DiskLruCacheWrapper
//之后通过DiskLruCacheWrapper的get方法获得缓存文件cacheFile
cacheFile = helper.getDiskCache().get(currentKey);
if (cacheFile != null) {
sourceKey = sourceId;
//取得能够加载这个缓存文件的Loaders
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
//如果获取到了modelLoaders,就会退出循环
}
}

loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
//先通过ModelLoader构造出LoadData对象
loadData = modelLoader.buildLoadData(cacheFile,
helper.getWidth(), helper.getHeight(), helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
//通过DataFetcher的loadData方法,加载缓存文件的数据
loadData.fetcher.loadData(helper.getPriority(), this);
}
}

//加载缓存文件的数据后,返回true
return started;
}

在该方法中,如果能够获取到缓存文件,就先得到能够加载这个缓存文件的ModelLoaders,之后通过ModelLoader构造出对应的LoadData,最后通过该LoadData的DataFetcher的loadData方法加载缓存文件的数据。

假如这里调用的ByteBufferFetcher的loadData方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
callback.onLoadFailed(e);
return;
}

callback.onDataReady(result);
}

成功的话会回调onDataReady方法,将加载到的数据传出去,先存放在DecodeJob中,之后进行相关操作:

1
2
3
4
5
6
7
8
9
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
//...

this.currentData = data;

//...
}

而失败的话会回调onLoadFailed方法,也是在DecodeJob中处理

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public void onDataFetcherFailed(Key attemptedKey, Exception e, DataFetcher<?> fetcher,
DataSource dataSource) {
//...

if (Thread.currentThread() != currentThread) {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
} else {
runGenerators();
}
}

可以看到,在加载数据失败后不会就此结束,而是重新执行runGenerators方法再次尝试获取数据。

对于第二种情况,假如state为DATA_CACHE(磁盘缓存策略为DiskCacheStrategy.DATA或DiskCacheStrategy.ALL),则执行DataCacheGenerator的startNext方法,该方法的过程ResourceCacheGenerator类似,就不多说了。

现在看第三种情况,当state为SOURCE时,对应的Generator为SourceGenerator,同样调用SourceGenerator的startNext方法:

SourceGenerator#startNext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 @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对象
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//通过DataFetcher的loadData方法加载数据
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}

该方法中,如果已经获取到了数据,就将数据添加到磁盘缓存中,之后如果可以从磁盘缓存加载数据就不再执行后面操作。否则的话,同样是先通过相应的ModelLoader获得LoadData对象,然后通过LoadData中的DataFetcher的loadData方法加载数据(例如通过url从网络加载图片资源)。

如果加载数据成功,会先在SourceGenerator中回调onDataReady方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 @Override
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
//判断是否要缓存到磁盘中
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
//如果要缓存到磁盘中,会先把数据保存起来,之后重新进入startNext方法(可能在其他子线程),将数据缓存到磁盘。
dataToCache = data;
cb.reschedule();
} else {
//不缓存到磁盘的话,就将数据传递出去,存放在DecodeJob中
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}

加载成功时,会判断是否要缓存到磁盘(如果是从网络加载的资源,当磁盘缓存策略为DiskCacheStrategy.DATA和DiskCacheStrategy.ALL时,会缓存起来),要缓存到磁盘时,会重新进入startNext方法并将数据缓存到磁盘。如果不缓存到硬盘就将数据传递出去。

如果加载数据失败,同样会重新执行runGenerators方法再次尝试获取数据。

分析到这里,Engine的load方法算是分析完毕了,这个方法是真正用于加载数据的,通过该方法可以了解到Glide的缓存机制。这里小结一下Engine的load方法的执行步骤:

小结

Engine#load的执行步骤

  1. 生成缓存key:该key是一个EngineKey对象,由传入的多个参数生成。之后通过缓存key获取缓存资源
  2. 首先从ActiveResources中获取缓存,ActiveResources是第一级缓存,它通过HashMap来存储数据,数据保存在WeakReference中,此外还有一个引用队列,当某个数据的弱引用对象被gc掉之后,其对应的Reference对象会加入到引用队列中。从引用队列获取到被gc掉的弱引用对象后就可以将这些对象从ActiveResources中删除。
  3. 如果ActiveResources中获取不到,就从内存中获取,内存缓存是第二级缓存。内存缓存使用了LRU算法,内部使用LinkedHashMap存储数据。LinkedHashMap内部可以设置为按照访问顺序进行排序,最近最少访问的在前面,很适合LRU算法。如果成功获取到缓存,就将缓存从内存中删除并将添加到ActiceResources中。
  4. 如果内存中也获取不到缓存,就会创建EngineJob和DecodeJob,DecodeJob是一个Runnable。EngineJob将DecodeJob提交到线程池中执行。DecodeJob根据资源的磁盘缓存策略,是缓存原图还是缓存转换后的图片,从磁盘中获取不同的缓存文件,获取缓存文件成功后,先得到能够加载该缓存文件的ModelLoader,之后通过ModelLoader构造出对应的LoadData,最后通过该LoadData的DataFetcher加载缓存文件的数据。加载数据成功会将数据传递出去,失败的话会重新尝试获取缓存文件并加载数据。
  5. 如果不能从磁盘中得到缓存,会继续在DecodeJob中通过相应的ModelLoader获得LoadData对象并加载数据,不过这次是从数据源加载数据,例如从通过url从网络加载数据。加载数据成功后,会判断是否要缓存到磁盘要缓存到磁盘时,会重新进入startNext方法并将数据缓存到磁盘。如果不缓存到硬盘就将数据传递出去。加载数据失败的话会重新尝试加载,因为可能其他的ModelLoader可以加载成功,所以要不断尝试,直到所有ModelLoader都尝试完。

参考

-------------    本文到此结束  感谢您的阅读    -------------
0%