上一篇文章分析了Glide中with与load方法的加载流程,如果没有看上一篇的请查看(点击打开链接),接下来继续分析into的加载流程。
一、into方法
public Target<TranscodeType> into(ImageView view) {
//检查是否在主线程,如果不在抛出异常
Util.assertMainThread();
//检查View是否为空,为空抛出异常
Preconditions.checkNotNull(view);
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
if (requestOptions.isLocked()) {
requestOptions = requestOptions.clone();
}
//判断View设置的requestOptions的类型,设置View的居中、裁剪、平铺等参数
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions.optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions.optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions.optionalFitCenter();
break;
case FIT_XY:
requestOptions.optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
//核心方法:1、buildImageViewTarget 2、into
return into(glideContext.buildImageViewTarget(view, transcodeClass), requestOptions);
}
1、buildImageViewTarget
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
//一个工厂方法,负责生产正确的数据类型,返回正确的实例对象
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
//返回Bitmap类型ViewTarget
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
//返回Drawable类型ViewTarget
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
}
不管是BitmapImageViewTarget还是DrawableImageViewTarget都继承自ImageViewTarget只是泛型中传递的参数不一样。他们的继承关系如下:
DrawableImageViewTarget/BitmapImageViewTarget ——> ImageViewTarget<Z> ——> ViewTarget<ImageView, Z> ——>BaseTarget<Z> ——> Target<R>(inteface) ——> LifecycleListener(inteface)
(1)LifecycleListener:是一个持有组件(比如 activity 或者 fragment等)生命周期状态信息的接口,用于监听Activity或者fragment的生命周期。
public interface LifecycleListener {
//开始加载组件
void onStart();
//停止加载组件
void onStop();
//销毁加载组件
void onDestroy();
}
(2)Target<R>(inteface):继承自LifecycleListener,观察泛型种参数View变化时候的声明周期。
public interface Target<R> extends LifecycleListener {
//给定初始宽高
int SIZE_ORIGINAL = Integer.MIN_VALUE;
//开始加载图片
void onLoadStarted(@Nullable Drawable placeholder);
//加载失败
void onLoadFailed(@Nullable Drawable errorDrawable);
//加载图片完成
void onResourceReady(@NonNull R resource, @Nullable Transition<? super R> transition);
//图片加载取消
void onLoadCleared(@Nullable Drawable placeholder);
//初始化尺寸
void getSize(@NonNull SizeReadyCallback cb);
//移除回调
void removeCallback(@NonNull SizeReadyCallback cb);
//设置Request
void setRequest(@Nullable Request request);
//获取Request
Request getRequest();
}
(3)BaseTarget<Z>:实现Target接口,他是一个抽象类,重写了Target中所有的抽象方法。
public abstract class BaseTarget<Z> implements Target<Z> {
private Request request;
//设置request对象
@Override
public void setRequest(@Nullable Request request) {
this.request = request;
}
//获取request对象
@Override
public Request getRequest() {
return request;
}
//取消加载
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
// Do nothing.
}
//开始加载图片
@Override
public void onLoadStarted(@Nullable Drawable placeholder) {
// Do nothing.
}
//加载图片失败
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
// Do nothing.
}
//开始加载动画
@Override
public void onStart() {
// Do nothing.
}
//加载动画停止
@Override
public void onStop() {
// Do nothing.
}
//图片销毁
@Override
public void onDestroy() {
// Do nothing.
}
}
(4)ViewTarget<ImageView, Z>:继承自BaseTarget,分为两大部分,第一部分用于View添加和移除的操作以及tag设置,这里面涉及到一个Request接口,主要用来加载请求资源时候的回调;另一个是内部类SizeDeterminer,它主要用于获取设置调整图片尺寸相关。
public abstract class ViewTarget<T extends View, Z> extends BaseTarget<Z> {
………………………………………………………………………省略部分代码……………………………………………………………………………………
public final ViewTarget<T, Z> clearOnDetach() {
if (attachStateListener != null) {
return this;
}
attachStateListener = new OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
//当View被添加到Window时候回调
resumeMyRequest();
}
@Override
public void onViewDetachedFromWindow(View v) {
//当View被被Window移除时候回调
pauseMyRequest();
}
};
maybeAddAttachStateListener();
return this;
}
@SuppressWarnings("WeakerAccess")
@Synthetic void resumeMyRequest() {
//获取在setRequest方法里面设置的tag
Request request = getRequest();
if (request != null && request.isPaused()) {
//获取request接口,设置加载View开始的回调
request.begin();
}
}
@SuppressWarnings("WeakerAccess")
@Synthetic void pauseMyRequest() {
//获取在setRequest方法里面设置的tag
Request request = getRequest();
if (request != null && !request.isCancelled() && !request.isPaused()) {
isClearedByUs = true;
//获取request接口,设置加载View结束的回调
request.pause();
isClearedByUs = false;
}
}
………………………………………………………………………省略部分代码……………………………………………………………………………………
static final class SizeDeterminer {
………………………………………………………………………省略尺寸计算代码……………………………………………………………………………………
}
(5)ImageViewTarget<Z>:继承自ViewTarget,并且实现Transition.ViewAdapter接口:
public interface Transition<R> {
interface ViewAdapter {
//获取View
View getView();
//获取Drawable
Drawable getCurrentDrawable();
//设置Drawable
void setDrawable(Drawable drawable);
}
//是否设置动画
boolean transition(R current, ViewAdapter adapter);
}
ImageViewTarget里面主要是处理View动画开启与敢关闭监听图片加载过程做出相应操作,如加载开始、加载中、加载错误、加载空布局等图片。BitmapImageViewTarget与此类似。
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>implements Transition.ViewAdapter {
private Animatable animatable;
//初始化View的尺寸
public ImageViewTarget(ImageView view) {
super(view);
}
//初始化View的尺寸
public ImageViewTarget(ImageView view, boolean waitForLayout) {
super(view, waitForLayout);
}
//获取当前View的Drawable对象
@Override
public Drawable getCurrentDrawable() {
return view.getDrawable();
}
//设置当前View的Drawable对象
@Override
public void setDrawable(Drawable drawable) {
view.setImageDrawable(drawable);
}
//设置加载占位图
@Override
public void onLoadStarted(@Nullable Drawable placeholder) {
super.onLoadStarted(placeholder);
setResourceInternal(null);
setDrawable(placeholder);
}
//设置加载失败
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
setResourceInternal(null);
setDrawable(errorDrawable);
}
//取消加载
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
super.onLoadCleared(placeholder);
if (animatable != null) {
animatable.stop();
}
setResourceInternal(null);
setDrawable(placeholder);
}
//加载完成
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
//开始动画
@Override
public void onStart() {
if (animatable != null) {
animatable.start();
}
}
//结束动画
@Override
public void onStop() {
if (animatable != null) {
animatable.stop();
}
}
//子类实现设置外部图片资源
private void setResourceInternal(@Nullable Z resource) {.
setResource(resource);
maybeUpdateAnimatable(resource);
}
private void maybeUpdateAnimatable(@Nullable Z resource) {
if (resource instanceof Animatable) {
animatable = (Animatable) resource;
animatable.start();
} else {
animatable = null;
}
}
//子类实现设置图片资源
protected abstract void setResource(@Nullable Z resource);
}
(6)DrawableImageViewTarget
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
public DrawableImageViewTarget(ImageView view) {
//View初始化
super(view);
}
@Override
protected void setResource(@Nullable Drawable resource) {
//设置图片
view.setImageDrawable(resource);
}
}
现在总结上部分,buildImageViewTarget返回的是ViewTarget:
(1)由RequestBuilder构造方法传递过来的class对象通过ImageViewTargetFactory创建对应XxxImageViewTarget。
(2)XxxImageViewTarget继承自ImageViewTarget,最终实现了View生命周期的监听,从而对View的加载的整个过程进行监听。
2、into
作用:创建新的请求,根据tag获取旧的请求并且进行比较,如果一致回收掉新建的请求,使用旧的request请求;否则清除旧的tag,添加新的请求并且开始请求。
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
@NonNull RequestOptions options) {
//是否为主线程
Util.assertMainThread();
//检查tag是否为nul
Preconditions.checkNotNull(target);
//检查设置的URL是否为空
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//获取配置参数
options = options.autoClone();
//创建新的请求对象,Request为一个接口,用于监控请求,请求过程请看(二、Request的创建过程)说明
Request request = buildRequest(target, targetListener, options);
//根据target获取到Request
Request previous = target.getRequest();
//如果和新建的请求和获取的请求一致,并且没有缓存,请求已经完成,则回收新建的请求recycle()
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
//如果旧的请求没有在运行,则开启之前请求
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
//清除tag的值
requestManager.clear(target);
//给tag设置新的request
target.setRequest(request);
//添加tag,开始请求
requestManager.track(target, request);
return target;
}
二、Request的创建过程分析
buildRequest没有处理其他事情,直接返回的是buildRequestRecursive方法,因此直接看buildRequestRecursive方法:
private Request buildRequestRecursive(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener, //请求监听相关接口
@Nullable RequestCoordinator parentCoordinator, //请求协调相关接口
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority, //RequestOptions设置的优先级
int overrideWidth, //RequestOptions设置的宽度
int overrideHeight, //RequestOptions设置的高度
RequestOptions requestOptions) {
………………………………………………………………………省略部分代码……………………………………………………………………………………
Request mainRequest =
buildThumbnailRequestRecursive(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions);
………………………………………………………………………省略部分代码……………………………………………………………………………………
}
接下来看看方法buildThumbnailRequestRecursive:
private Request buildRequestRecursive(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener, //请求监听相关接口
@Nullable RequestCoordinator parentCoordinator, //请求协调相关接口
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority, //RequestOptions设置的优先级
int overrideWidth, //RequestOptions设置的宽度
int overrideHeight, //RequestOptions设置的高度
RequestOptions requestOptions) {
………………………………………………………………………省略部分代码……………………………………………………………………………………
Request mainRequest =
buildThumbnailRequestRecursive(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions);
………………………………………………………………………省略部分代码……………………………………………………………………………………
}
接下来看看方法buildThumbnailRequestRecursive:
private Request buildThumbnailRequestRecursive(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
RequestOptions requestOptions){
//与略缩图相关设置判断逻辑判断,直接进入obtainRequest
………………………………………………………………………省略部分代码……………………………………………………………………………………
return obtainRequest(
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight);
}
}
obtainRequest调用的是SingleRequest类中obtain方法,他是一个单独的加载资源类,实现了Request接口:
public static <R> SingleRequest<R> obtain(
Context context,
GlideContext glideContext,
Object model,
Class<R> transcodeClass,
RequestOptions requestOptions,
int overrideWidth,
int overrideHeight,
Priority priority,
Target<R> target,
RequestListener<R> targetListener,
RequestListener<R> requestListener,
RequestCoordinator requestCoordinator,
Engine engine,
TransitionFactory<? super R> animationFactory) {
SingleRequest<R> request = (SingleRequest<R>) POOL.acquire();
if (request == null) {
request = new SingleRequest<>();
}
//这里调用init方法进行构造方法赋值,这样Request的实现类就获得了初始值
request.init(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListener,
requestCoordinator,
engine,
animationFactory);
return request;
}
以上就是Request的创建过程过程,这个过程完成了Request的初始,但是整个请求过程还没开始。
三、请求加载的过程分析
1、begin方法开始加载
在1.2 into方法中有previous.begin(); requestManager.track(target, request);两行代码,track最终调用的还是Request的begin方法,表示开启一个异步的请求,在Request的实现类SingleRequest方法中找到该方法。
@Override
public void begin() {
//验证上一次是否请求完毕或者clear,否则抛出异常
assertNotCallingCallbacks();
//检查资源是否释放
stateVerifier.throwIfRecycled();
//计算开始时间
startTime = LogTime.getLogTime();
//判断图片加载途径是否为空,为空则抛出异常
if (model == null) {
//判断宽高是否>0
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
//加载未完成
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
//加载完成
if (status == Status.COMPLETE) {
//检查资源是否存在,存在的话从内存中进行加载
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
//设置加载状态
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 核心方法,如下
onSizeReady(overrideWidth, overrideHeight);
} else {
//在SizeDeterminer中重新进行尺寸测量
target.getSize(this);
}
//设置占位图
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
//设置开始加载的监听接口,设置开始加载的时候的占位图
target.onLoadStarted(getPlaceholderDrawable());
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
2、onSizeReady方法调整宽高
@Override
public void onSizeReady(int width, int height) {
………………………………………………………………………省略部分代码……………………………………………………………………………………
//重新设置status状态
status = Status.RUNNING;
//获取设置的转换因子(0-1)之间,防止图片过大或者加载略缩图
float sizeMultiplier = requestOptions.getSizeMultiplier();
//获取转换后的宽高值
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
//使用engine进行加载
loadStatus = engine.load(
glideContext,//Glide上下文对象,详情查看上一篇文章
model,//请求地址URL、uri等等
requestOptions.getSignature(),//内存缓存和磁盘缓存的键
this.width,
this.height,
requestOptions.getResourceClass(),//Object的class对象
transcodeClass,//泛型参数,例如Bitmap,Drawable等
priority, //优先级
requestOptions.getDiskCacheStrategy(), //磁盘缓存的类型:枚举
requestOptions.getTransformations(), //动画集合:HashMap类型
requestOptions.isTransformationRequired(), //是否支持动画播放
requestOptions.isScaleOnlyOrNoTransform(), //是否支持缩放处理
requestOptions.getOptions(), //获取Options对象,Options是一个磁盘、内存缓存处理键的相关类
requestOptions.isMemoryCacheable(), //是否开启内存缓存
requestOptions.getUseUnlimitedSourceGeneratorsPool(), //true
requestOptions.getUseAnimationPool(),开启无线内存缓存模式,该模式影响性能
requestOptions.getOnlyRetrieveFromCache(), //优先加载缓存资源
this);
}
3、engine.load方法进行加载
engine类的初始化操作来自于上面讲的obtain方法,最终的结果来自于GlideContext类的getEngine()方法,关于该类详情请查看上一篇文章点击打开链接,engine类的load方法是根据跟定的参数进行加载,需要注意它必须是在主线程,省略部分代码:
public <R> LoadStatus load(………省略参数…) {
//检查是否在主线程
Util.assertMainThread();
//根据当前参数生成内存缓存的key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//1、从当前活跃的线程资源池中加载
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
//2、从内存中加载
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
//3、从本地缓存中加载
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
//4、重新请求
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
………………………………………………………………………省略部分代码……………………………………………………………………………………
return new LoadStatus(cb, engineJob);
}
从上文中中可以看出他是经过四步进行加载的:
第一步:从当弱引用中加载
第二步:从内存中加载
第三步:从本地缓存中加载
第四步:从网络请求中加载
这四步,一旦有一步加载成功,就会设置设置资源加载成功或者异常的回调到onResourceReady方法,并且立即返回,不再进行接下来的加载,接下来分别看着四步请求过程。
四、加载的过程分析
上面说了图片的加载过程分为四步,前三步伴随着Glide的缓存加载的过程,也是Glide缓存机制的核心内容。这四步中需要用的一个键key,key的生成是EngineKey重写hashCode方法依据传递的参数生成的一个int类型的数据,除此之外还重写了equals方法,用于比较key是否为同一个。
1、从弱引用中加载
@Nullable
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
//无内存缓存,则第一步加载失败,继续走第二步加载
if (!isMemoryCacheable) {
return null;
}
//获取EngineResource,他是一个资源的包装类,用于资源的释放与获取
EngineResource<?> active = activeResources.get(key);
if (active != null) {
//进行资源释放,释放规则:用一个变量进行标记,如果当前引用一次则+1,释放一次则-1,有点像垃圾回收的算法
active.acquire();
}
return active;
}
深究activeResources.get(key)方法,会看到他的资源缓存机制,他是把资源放在一个HashMap集合中,集合的键为传递过来的key值为ResourceWeakReference弱引用,到这里才明白,第一步的加载过程本质上是从弱引用中加载资源。
@Nullable
EngineResource<?> get(Key key) {
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
return null;
}
2、从内存中加载
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
//无内存缓存,则第一步加载失败,继续走第二步加载
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
//进行资源释放,释放规则:用一个变量进行标记,如果当前引用一次则+1,释放一次则-1,有点像垃圾回收的算法
cached.acquire();
//进行弱引用缓存,以保证第一步加载有数据,缓存的过程是保存在HashMap集合里面
activeResources.activate(key, cached);
}
return cached;
}
getEngineResourceFromCache方法如下:
private EngineResource<?> getEngineResourceFromCache(Key key) {
//根据key从MemoryCache移除之前的缓存,返回的值移除的缓存内容,可以为null
Resource<?> cached = cache.remove(key);
final EngineResource<?> result;
if (cached == null) {
//如果cached为null,则说明没有缓存,进行第三步加载
result = null;
} else if (cached instanceof EngineResource) {
//直接返回当前资源
result = (EngineResource<?>) cached;
} else {
//如果cached不属于EngineResource,则根据cached新建EngineResource,值接返回该对象
result = new EngineResource<>(cached, true /*isMemoryCacheable*/, true /*isRecyclable*/);
}
return result;
}
3、从本地缓存中加载
//EngineJob加载资源或者移除资源的回调通知相关类,
//key:缓存的键;onlyRetrieveFromCache:是否仅从磁盘缓存加载
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
//添加回调
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
//后面看,先看第四步
return new LoadStatus(cb, current);
}
4、从网络请求中加载
(1)获取engineJob对象:主要用来设置加载过程中监听回调。
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
(2)获取decodeJob对象:主要是从缓存或者网络来的数据进行加载解析,他是一个Runnable实例对象,作为ExecutorService的参数。
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
(3)进行任务缓存
jobs.put(key, engineJob);
Jobs类中包含了两个HashMap集合,一个是jobs,另一个是onlyCacheJobs,使用哪个集合进行缓存是根据传递的参数进行选择:
private Map<Key, EngineJob<?>> getJobMap(boolean onlyRetrieveFromCache) {
return onlyRetrieveFromCache ? onlyCacheJobs : jobs;
}
(4)设置加载完成和加载失败回调
engineJob.addCallback(cb);
void addCallback(ResourceCallback cb) {
Util.assertMainThread();
stateVerifier.throwIfRecycled();
if (hasResource) {
//加载成功,设置资源加载成功的回调
cb.onResourceReady(engineResource, dataSource);
} else if (hasLoadFailed) {
//加载失败,设置资源加载失败的回调
cb.onLoadFailed(exception);
} else {
//否则添加到ResourceCallback集合
cbs.add(cb);
}
(5)开启线程,开始执行加载
engineJob.start(decodeJob);
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
//返回true,则尝试在磁盘缓存中加载;返回false,则从网络资源获取
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
//执行线程
executor.execute(decodeJob);
}
(6)返回LoadStatus状态
return new LoadStatus(cb, engineJob);
接下来依据着五步进行网络请求加载分析。
五、网络请求的过程分析
在上面的第五步中开启线程,开始执行加载,可以看出执行线程操作的时候是在GlideExecutor类中,它实现了ExecutorService接口,操作Glide网络请求的线程调度。上一个(2)中提提到decodeJob是Runnable的实例对象,那么我们看看run方法的实现数据的加载:
@Override
public void run() {
TraceCompat.beginSection("DecodeJob#run");
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
//true:表示取消加载了,通知加载失败
notifyFailed();
return;
}
//下面看看runWrapped方法
runWrapped();
} catch (Throwable t) {
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
} finally {
if (localFetcher != null) {
localFetcher.cleanup();
}
TraceCompat.endSection();
}
}
private void runWrapped() {
//一个枚举类型的数据,Why we're being executed again,包括如下三种类型:
switch (runReason) {
case INITIALIZE:
//第一次提交加载初始化,返回初始化状态
stage = getNextStage(Stage.INITIALIZE);
//数据加载状态监听
currentGenerator = getNextGenerator();
//和第三步一样直接看第二步
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
//从磁盘加载切换到网络加载
runGenerators();
break;
case DECODE_DATA:
//切换到我们所在的当前线程加载数据
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
1、初始化阶段INITIALIZE
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
//初始化需要执行的操作
//diskCacheStrategy:磁盘缓存
//Stage.RESOURCE_CACHE:从磁盘加载
//如果没有磁盘缓存,执行下一步,RESOURCE_CACHE
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:
// 如果设置仅从磁盘加载省略过这一步
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
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);
}
}
2、磁盘缓存加载 SWITCH_TO_SOURCE_SERVICE
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
//同上分析
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
//看下面
reschedule();
return;
}
}
@Override
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
3、开启线程网络加载DECODE_DATA
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);
} else {
runGenerators();
}
}
六、缓存机制分析
前一部分分析中涉及到Glide的缓存内容,但是没有着重进行讲解,关于缓存部分分为两大部分,内存缓存和磁盘缓存,在Glide的缓存部分中有两个涉及到缓存的API:skipMemoryCache、diskCacheStrategy分别表示是否跳过内存缓存和磁盘缓存策略设置,先来看看内存缓存。
1、缓存key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,resourceClass, transcodeClass, options);
从上面的方法可以看出,缓存key的生成需要的参数非常多,EngineKey实现了key接口,复写了equals,hashCode,toString,updateDiskCacheKey几个方法,众多的参数和比较方法的重写保证了key的唯一性,当任何一个参数变化,都会认为是不同的key。
2、内存缓存
requestOptions.skipMemoryCache(true);
(1)内存缓存策略
在上一篇文章中提到GlideBuilder这个类,在构建Glide的时候就会创建内存memoryCache对象:
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
现在就来看看内存缓存类LruResourceCache,他的继承关系:LruResourceCache -> LruCache 并且实现了MemoryCache接口。这说明Glide的内存缓存是依据LruCache算法为基础进行缓存的,这里不在分析LruCache算法。
(2)内存缓存大小
Glide中规定了内存缓存的大小为三类:低内存、正常内存、高内存,默认是正常内存,存在于MemoryCategory枚举中。
public enum MemoryCategory {
LOW(0.5f),
NORMAL(1f),
HIGH(1.5f);
}
通过trimMemory方法进行设置:
public void trimMemory(int level) {
// Engine asserts this anyway when removing resources, fail faster and consistently
Util.assertMainThread();
// memory cache needs to be trimmed before bitmap pool to trim re-pooled Bitmaps too. See #687.
memoryCache.trimMemory(level);
bitmapPool.trimMemory(level);
arrayPool.trimMemory(level);
}
(3)清除内存缓存
Glide.get(this).clearMemory();//需要在UI线程
3、磁盘缓存
requestOptions.diskCacheStrategy(DiskCacheStrategy.RESOURCE);
(1)磁盘缓存目录
在上一篇文章中说了,磁盘缓存路径是在Glide类中,默认缓存在CacheDir的"image_manager_disk_cache"文件夹下面,关于Glide类请查看上一篇文章。
(2)磁盘缓存策略
磁盘缓存使用的是DiskLruCache类,包括了五大缓存类型类型:ALL、NONE、DATA、RESOURCE、AUTOMATIC。
- DiskCacheStrategy.ALL 使用DATA和RESOURCE缓存远程数据,仅使用RESOURCE来缓存本地数据。
- DiskCacheStrategy.NONE 不使用磁盘缓存
- DiskCacheStrategy.DATA 在资源解码前就将原始数据写入磁盘缓存
- DiskCacheStrategy.RESOURCE 在资源解码后将数据写入磁盘缓存,即经过缩放等转换后的图片资源。
- DiskCacheStrategy.AUTOMATIC 根据原始图片数据和资源编码策略来自动选择磁盘缓存策略。
(3)清除磁盘缓存
Glide.get(MainActivity.this).clearDiskCache();//需要在子线程
至此,Glide加载流程分析到此结束!