一、源码分析:
1、with()
2、load()
3、into()
二、缓存机制
1、Glide缓存机制简介
1.1缓存的图片资源
Glide 需要缓存的 图片资源 分为两类:
原始图片(Source) :即图片源的图片初始大小 & 分辨率。
转换后的图片(Result) :经过尺寸缩放和大小压缩等处理后的图片。
当使用 Glide加载图片时,Glide默认 根据 View视图对图片进行压缩 & 转换,而不显示原始图(这也是Glide加载速度高于Picasso的原因)。
1.2 缓存机制设计
Glide的缓存功能设计成 二级缓存:内存缓存和磁盘缓存。
缓存读取顺序:内存缓存 –> 磁盘缓存 –> 网络。
内存缓存默认开启Glide中,内存缓存 & 磁盘缓存相互不影响,独立配置。
可缓存原始图片 & 缓存转换过后的图片,用户自行设置
2、Glide 缓存功能介绍
Glide 的缓存功能分为:内存缓存 & 磁盘缓存
2.1、内存缓存
作用:防止应用重复将图片数据读取到内存当中只缓存转换过后的图片。
实现原理:Glide的内存缓存实现是基于:LruCache 算法(Least Recently Used) 和弱引用机制
LruCache算法:将 最近使用的对象 用强引用的方式 存储在LinkedHashMap中 当缓存满时 ,将最近最少使用的对象从内存中移除 。
弱引用:弱引用的对象具备更短生命周期,当JVM进行垃圾回收时,一旦发现弱引用对象,都会进行回收(无论内存充足否)
2.2、磁盘缓存
作用:防止应用 重复从网络或其他地方重复下载和读取数据
实现原理 :使用Glide 自定义的DiskLruCache算法
该算法基于 Lru 算法中的DiskLruCache算法,具体应用在磁盘缓存的需求场景中
该算法被封装到Glide自定义的工具类中(该工具类基于Android 提供的DiskLruCache工具类
三、 Glide 缓存流程 解析
1、生成缓存Key
Glide 实现内存 & 磁盘缓存是根据图片的缓存Key进行唯一标识,即根据图片的缓存Key去缓存区找对应的缓存图片,生成缓存 Key 的代码发生在Engine类的 load()中
public synchronized <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<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
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);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
2、创建缓存对象 LruResourceCache
LruResourceCache对象是在创建 Glide 对象时创建的,就是GlideBuilder类的memoryCache
@NonNull
Glide build(@NonNull Context context) {
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
if (diskCacheExecutor == null) {
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
if (animationExecutor == null) {
animationExecutor = GlideExecutor.newAnimationExecutor();
}
if (memorySizeCalculator == null) {
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
if (connectivityMonitorFactory == null) {
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
animationExecutor,
isActiveResourceRetentionAllowed);
}
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
}
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled);
}
3、从内存缓存中获取缓存图片
没错,还是Engine类,loadFromActiveResources()和loadFromCache()
弱引用机制的内存缓存获取缓存
@Nullable
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
LruCache算法机制的内存缓存获取缓存
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
activeResources.activate(key, cached);
}
return cached;
}
4、开启加载图片线程
若无法从内存缓存里获得缓存的图片,Glide就会开启加载图片的线程
但在该线程开启后,Glide并不会马上去网络 加载图片,而是采取采用Glide的第2级缓存:磁盘缓存去获取缓存图片
5、从磁盘缓存中获取缓存图片
若无法从内存缓存里获得缓存的图片,就会磁盘缓存去获取缓存图片
6、从网络获取图片资源
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
7、写入磁盘缓存
8、写入内存缓存
9、写入弱应用缓存
10、显示图片
在将图片写入内存缓存和磁盘缓存后,图片最终显示出来
在下次加载时,将通过二级缓存从而提高图片加载效率。
网友评论