在上一篇文章中,我们简要的讲了Glide加载一张网络图片的基本流程,整个流程有点长,也有点多,很多东西没有细讲。所以会对Glide一些重要的东西单独写文章讲解,以便大家对Glide细节了解更深。假如说一个优秀的网络图片加载框架最重要的是什么,它的缓存机制无疑是最重要的,它决定框架加载的资源统筹。在看这一篇文章假如没有看Glide源码之基本流程加载建议先这这一篇,让你对整个流程有大概的了解。
Glide缓存设计
Glide分成内存缓存和磁盘缓存两个:
- 内存缓存:基于基于弱引用和LruCache(先看弱引用有无缓存,再看LruCache有无缓存)
- 磁盘缓存:基于DiskLruCache进行封装(当内存没有时,看磁盘有无,有就获取没有只网络获取)
大致流程
内存缓存->磁盘缓存->网络加载
当网络加载完,再把图片缓存加载到内存和磁盘
加载流程
首先我们看一下有关上一篇的加载代码:
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, /* isLoadedFromAlternateCacheKey= */ false);
return null;
}
我们先看看keyFactory.buildKey()方法:
EngineKey buildKey(
Object model,
Key signature,
int width,
int height,
Map<Class<?>, Transformation<?>> transformations,
Class<?> resourceClass,
Class<?> transcodeClass,
Options options) {
return new EngineKey(
model, signature, width, height, transformations, resourceClass, transcodeClass, options);
}
//EngineKey类源码
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;
}
省略代码....
}
EngineKey很简单,就是存贮宽高,签名等参数生成对象,然后重写equals()和hashCode()方法,让他们不同宽高都返回不同的key,只有参数一样才会返回一样的key,确保资源唯一性。
上面很简单,接着我们再看看获取内存缓存的方法loadFromMemory()代码如下:
private EngineResource<?> loadFromMemory(EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
return null;
}
//看内存的弱引用缓存有无对应key,有则返回
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return active;
}
//看内存的Lrucache缓存有无对应的key,有则返回
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
}
return null;
}
弱引用缓存loadFromActiveResources():
private EngineResource<?> loadFromActiveResources(Key key) {
//从根据key从弱引用对象获取数据
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
//get()方法源码:
synchronized EngineResource<?> get(Key key) {
//从activeEngineResources取出弱引用对象
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
return null;
}
//获取弱引用对象数据缓存
EngineResource<?> active = activeRef.get();
if (active == null) {
//假如等于null,就证明被垃圾回收机制回收
cleanupActiveReference(activeRef);
}
return active;
}
这里的activeEngineResources是什么呢,其实就是一个hashmap对象:
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
所以弱引用对象是放在HashMap那里的,然后拿到对象看看资源有没有被垃圾回收机制回收,假如被回收了,就调用cleanupActiveReference()方法,源码如下:
//cleanupActiveReference()方法源码:
void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
synchronized (this) {
//删除该弱引用对象
activeEngineResources.remove(ref.key);
//判断缓存是否可用
if (!ref.isCacheable || ref.resource == null) {
return;
}
}
//恢复EngineResource,其中这个对象封装了图片资源
EngineResource<?> newResource = new EngineResource<>(ref.resource, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ false, ref.key, listener);
//回调,该listener为Engine对象
listener.onResourceReleased(ref.key, newResource);
}
接着会回调Engine的onResourceReleased()方法,代码如下:
public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
//删除弱引用
activeResources.deactivate(cacheKey);
//设置了缓存
if (resource.isMemoryCacheable()) {
//将弱引用数据存在内存缓存LruCache
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource, /*forceNextFrame=*/ false);
}
}
也就是说弱引用没有了,就放在内存缓存LruCache,然后下一步在内存缓存加载,看有没有,就可以从LruCache获取到。
loadFromCache()
假如弱引用没有的话就会调loadFromCache()从LruCache获取,现在方法源码:
private EngineResource<?> loadFromCache(Key key) {
//从LruCache获取图片资源
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
//引用加一
cached.acquire();
activeResources.activate(key, cached);
}
return cached;
}
//图片资源具体方法
private EngineResource<?> getEngineResourceFromCache(Key key) {
//从LruCache获取图片资源并且删除缓存
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;
}
获取图片资源之后就是调 activeResources.activate(key, cached),把他放在弱引用:
synchronized void activate(Key key, EngineResource<?> resource) {
ResourceWeakReference toPut =new ResourceWeakReference(
key, resource, resourceReferenceQueue, isActiveResourceRetentionAllowed);
//将内存缓存存入弱引用缓存中
ResourceWeakReference removed = activeEngineResources.put(key, toPut);
if (removed != null) {
removed.reset();
}
}
这样就保证了弱引用没有,LruCache有,就直接把资源存入弱引用同时删除LruCache,同时也让图片不会被LruCache算法回收掉。
假如弱引用缓存和内存缓存都没有的时候,就要看磁盘缓存或者网络加载
waitForExistingOrStartNewJob()
private <R> LoadStatus waitForExistingOrStartNewJob(.....) {
//省略代码.....
//创建EngineJob对象,加载图片
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);
}
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
可以看到,用线程池开线程来加载图片,会调用DecodeJob的run()方法:
public void run() {
//重点运行了runWrapped(),进行加载
runWrapped();
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//获取加载状态
stage = getNextStage(Stage.INITIALIZE);
//获取加载对应的Generator
currentGenerator = getNextGenerator();
//执行相应的Generator
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
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);
}
}
这里分别有三个Generator,对应的功能功能如下:
- ResourceCacheGenerator (处理解码之后的资源缓存Generator)
- DataCacheGenerator (处理源数据的缓存G的enerator)
- SourceGenerator (处理网络获取数据资源的Generator)
最后的runGenerators(),就是针对Generator进行运行处理,代码如下:
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled
&& currentGenerator != null
//startNext()方法就是执行Generator的方法
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
ResourceCacheGenerator
我们先来看看ResourceCacheGenerator的startNext()方法吧:
public boolean startNext() {
List<Key> sourceIds = helper.getCacheKeys();
//省略代码...
Key sourceId = sourceIds.get(sourceIdIndex);
Class<?> resourceClass = resourceClasses.get(resourceClassIndex);
Transformation<?> transformation = helper.getTransformation(resourceClass);
///生产缓存数据的key,这个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;
//该modeLoaders的类型为File类型的
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
//获取加载数据相应的ModelLoader
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
//生成加载器,这里生成的是ByteBufferFileLoader
loadData = modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
stdarted = true;
//调用ByteBufferFileLoader的loadData进行数据加载
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
ByteBufferFileLoader又有一个内部类ByteBufferFetcher,最终会调用ByteBufferFetcher的loadData()方法:
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
result = ByteBufferUtil.fromFile(file);
callback.onDataReady(result);
} catch (IOException e) {
callback.onLoadFailed(e);
}
}
public static ByteBuffer fromFile(@NonNull File file) throws IOException {
RandomAccessFile raf = null;
FileChannel channel = null;
try {
long fileLength = file.length();
raf = new RandomAccessFile(file, "r");
channel = raf.getChannel();
return channel.map(FileChannel.MapMode.READ_ONLY, 0, fileLength).load();
} finally {
if (channel != null) {
try {
channel.close();
} catch (IOException e) {
}
}
if (raf != null) {
try {
raf.close();
} catch (IOException e) {
}
}
}
}
可以看到,他们是通过ByteBufferUtil来把文件转成数据,底层是通过RandomAccessFile和FileChannel来转化的,然后通过ResourceCacheGenerator的onDataReady进行回调,看回调代码:
ResourceCacheGenerator.onDataReady()
public void onDataReady(Object data) {
cb.onDataFetcherReady(
sourceKey, data, loadData.fetcher, DataSource.RESOURCE_DISK_CACHE, currentKey);
}
对应这DecodeJob的onDataFetcherReady()方法:
public void onDataFetcherReady(
Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
this.isLoadingFromAlternateCacheKey = sourceKey != decodeHelper.getCacheKeys().get(0);
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
//处理获取的数据
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
//转换图片资源
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
//处理转换成功图片
notifyEncodeAndRelease(resource, currentDataSource, isLoadingFromAlternateCacheKey);
} else {
runGenerators();
}
}
private void notifyEncodeAndRelease(
Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
//省略代码
//继续回调把资源返回给上一层
notifyComplete(result, dataSource, isLoadedFromAlternateCacheKey);
stage = Stage.ENCODE;
try {
if (deferredEncodeManager.hasResourceToEncode()) {
//资源缓存到磁盘
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
onEncodeComplete();
}
private void notifyComplete(Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource, isLoadedFromAlternateCacheKey);
}
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();
}
}
回调的流程可以参考我的上一篇文章Glide源码之基本流程加载
DataCacheGenerator
接着看DataCacheGenerator,先看startNext()代码:
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
Key sourceId = cacheKeys.get(sourceIdIndex);
//生成缓存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;
}
DataCacheGenerator的startNext()和ResourceCacheGenerator大致相似,唯一不同的是生成key的参数不一样,原生图片不需要宽高,配置等参数,其他基本相同,没啥讲的
SourceGenerator的startNext(),先看核心代码:
public boolean startNext() {
//省略代码...
startNextLoad(loadData);
//省略代码...
}
private void startNextLoad(final LoadData<?> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {
@Override
public void onDataReady(@Nullable Object data) {
if (isCurrentRequest(toStart)) {
onDataReadyInternal(toStart, data);
}
}
@Override
public void onLoadFailed(@NonNull Exception e) {
if (isCurrentRequest(toStart)) {
onLoadFailedInternal(toStart, e);
}
}
});
}
而这里的loadData对应的是HttpUrlFetcher的loadData()方法,
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException e) {
callback.onLoadFailed(e);
} finally {
}
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers) throws HttpException {
//省略代码...
//配置连接参数
urlConnection = buildAndConfigureConnection(url, headers);
try {
//于服务器连接
urlConnection.connect();
stream = urlConnection.getInputStream();
} catch (IOException e) {
throw new HttpException(
"Failed to connect or obtain data", getHttpStatusCodeOrInvalid(urlConnection), e);
}
if (isCancelled) {
return null;
}
final int statusCode = getHttpStatusCodeOrInvalid(urlConnection);
if (isHttpOk(statusCode)) {
//连接成功,获取输入流
return getStreamForSuccessfulRequest(urlConnection);
} else if (isHttpRedirect(statusCode)) {
String redirectUrlString = urlConnection.getHeaderField(REDIRECT_HEADER_FIELD);
URL redirectUrl;
try {
redirectUrl = new URL(url, redirectUrlString);
} catch (MalformedURLException e) {
throw new HttpException("Bad redirect url: " + redirectUrlString, statusCode, e);
}
cleanup();
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else if (statusCode == INVALID_STATUS_CODE) {
throw new HttpException(statusCode);
} else {
try {
throw new HttpException(urlConnection.getResponseMessage(), statusCode);
} catch (IOException e) {
throw new HttpException("Failed to get a response message", statusCode, e);
}
}
}
private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
throws HttpException {
try {
if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
int contentLength = urlConnection.getContentLength();
stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
} else {
//核心代码,底层默认通过HttpURLConnection获取数据流
stream = urlConnection.getInputStream();
}
} catch (IOException e) {
throw new HttpException(
"Failed to obtain InputStream", getHttpStatusCodeOrInvalid(urlConnection), e);
}
return stream;
}
从源码可以看出SourceGenerator是默认通过HttpURLConnection进行网络访问获取数据。接着看SourceGenerator的onDataReady()调用的onDataReadyInternal方法:
void onDataReadyInternal(LoadData<?> loadData, Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
//判断有无设置缓存
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
//假如设置缓存
dataToCache = data;
cb.reschedule();
} else {
cb.onDataFetcherReady(
loadData.sourceKey,
data,
loadData.fetcher,
loadData.fetcher.getDataSource(),
originalKey);
}
}
开启了磁盘缓存会调用DecodeJob的reschedule()方法:
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
public void reschedule(DecodeJob<?> job) {
//用线程池开启线程运行
getActiveSourceExecutor().execute(job);
}
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
//重新调用run方法
runWrapped();
} catch (CallbackException e) {
throw e;
} catch (Throwable t) {
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
throw t;
} finally {
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
可以发现,有重新调用的runWrapped()方法了,接着又是重新执行SourceGenerator的startNext()方法,只不过这次的执行不同了,
public boolean startNext() {
//第二次进入
//dataToCache不等于null,为之前下载的原始图片
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
//调用disklrucache缓存
cacheData(data);
}
//因为有网络下载的图片资源,所以不为空,会用SourceCacheGenerator获取图片资源
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());
//DiskLrucache保存图片
helper.getDiskCache().put(originalKey, writer);
} finally {
loadData.fetcher.cleanup();
}
//生成DataCacheGenerator对象,用来加载刚保存的磁盘缓存
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
}
用DiskLrucache保存图片图片后,会用DataCacheGenerator去加载资源。
小结:
Glide中首先会读取转换后的图片的缓存,然后再读取原始图片的缓存。但是存储的时候恰恰相反,首先存储的是原始图片的缓存,再存储转换后的图片。
网友评论