Glide4.11源码分析(一)生命周期的绑定
Glide4.11源码分析(二)三级缓存之内存缓存
Glide4.11源码分析(三)子线程执行的那些事儿及本地缓存
上文讲了Glide.with(activity)
方法的流程,获取到了RequestManager
对象,梳理出来了RequestManager
和Fragment
生命周期绑定的过程。这篇文章我们看看看RequestManager
的load过程。
RequestBuilder<Drawable> builder = requestManager.load("http://www.xxx.com/pic")
先看下返回的RequestBuilder是什么东西
> 代码片段9
//A generic class that can handle setting options and staring loads for generic resource types.
//Type parameters:
//<TranscodeType> – The type of resource that will be delivered to the Target.
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> {
//略..
private final Context context;
private final RequestManager requestManager;
private final Class<TranscodeType> transcodeClass;
//...略...
}
通用类,可以处理通用资源类型的设置选项和启动加载过程。RequestBuilder
继承自BaseRequestOptions
,传递的泛型类型是Target要价在的资源的类型。
看下RequestManager.load
方法是如何获取RequestBuilder
类对象的
> 代码片段10
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
/**
* 这个中调用as方法传递的是Drawable类对象
*/
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(@NonNull Class<ResourceType> resourceClass) {
//通过new创建RequestBuilder
return new RequestBuilder<>(glide, this, resourceClass, context);
}
/**
* RequestBuilder构造方法 赋值成员变量transcodeClass 为上面传递过来的Drawable.class后面要用到
*/
protected RequestBuilder(@NonNull Glide glide, RequestManager requestManager,Class<TranscodeType> transcodeClass, Context context) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass;
this.context = context;
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.glideContext = glide.getGlideContext();
//将RequestListener添加到requestListeners列表中
initRequestListeners(requestManager.getDefaultRequestListeners());
//设置选项
apply(requestManager.getDefaultRequestOptions());
}
RequestBuilder
有了,然后调用了RequestBuilder
的load方法,并最终调用它的loadGeneric
方法,这个方法就是设置了成员变量model的值,此model就用来表示要加载的数据源。
> 代码片段11
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
此方法并没有直接加载图片,接着往下看placeholder方法
> 代码片段12
@CheckResult
public T placeholder(@DrawableRes int resourceId) {
if (isAutoCloneEnabled) {//默认false,通过调用autoClone方法修改为true
return clone().placeholder(resourceId);
}
//设置placeholderId
this.placeholderId = resourceId;
fields |= PLACEHOLDER_ID;
placeholderDrawable = null;
fields &= ~PLACEHOLDER;
return selfOrThrowIfLocked();
}
if判断内部的逻辑是通过深拷贝获取一个builder
副本。这里默认不会走if中判断,只是修改成员变量placeholderId
和fields
的值,并返回builder。接下来的error方法跟这个逻辑相同,继续往下走,看centerCrop方法:
> 代码片段13
@NonNull
@CheckResult
public T centerCrop() {
//DownsampleStrategy.CENTER_OUTSIDE 就是CenterOutside 对象
return transform(DownsampleStrategy.CENTER_OUTSIDE, new CenterCrop());
}
@CheckResult
final T transform(@NonNull DownsampleStrategy downsampleStrategy , @NonNull Transformation<Bitmap> transformation) {
if (isAutoCloneEnabled) {
return clone().transform(downsampleStrategy, transformation);
}
//这里设置option为CenterOutside类型的
downsample(downsampleStrategy);
//这里应用变换,其实有个变换集合transformations,会存储变换类型。这里就是存储了变换类型
return transform(transformation);
}
接下来看into方法,上代码:
> 代码片段14
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
///略。。
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,//这个值是根据imageview的scaleType值,采用对应的requestOption
Executors.mainThreadExecutor());
}
glideContext
是调用Glide构造方法的时候创建的,transcodeClass
参数就是我们在生成RequestBuilder
的时候,调用as(Drawable.class)方法传进来的,忘记了的同学可以上去找一找。第4个参数Executors.mainThreadExecutor()
,是一个创建了个主线程的线程池,需要展示的数据的时候用到,后面还会讲到。下面先看下glideContext
的buildImageViewTarget
方法:
> 代码片段15
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
//imageViewTargetFactory是创建glideContext的时候new出来的
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
public <Z> ViewTarget<ImageView, Z> buildTarget(
@NonNull ImageView view, @NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
clazz就是前面调用as方法返回的结果,所以上面的buildTarget
方法会走else if里面的逻辑 生成DrawableImageViewTarget
对象并强转为ViewTarget
,下面讲讲这个ViewTarget
1、首先ViewTarget间接实现了LifecycleListener
接口,这个接口就是加载过程中的生命周期回调;
2、ViewTarget用来将Bitmap加载到View中,内部有个泛型T就是加载进去的目标类型,比如ImaeView;
3、ViewTarget还可以实现图片的复用,并通过View.setTag(Object object)方法来存储图片的源信息以达到复用的目的,比如在ListView中的复用;
4、ViewTarget中有两个方法分别是setRequest(Request request)
和getRequest()
。如下
> 代码片段16
/**
* 通过setTag来存储Request
*/
@Override
public void setRequest(@Nullable Request request) {
setTag(request);
}
/**
* 通过getTag获取存储在view的request
* View尽量不要使用setTag,因为有可能导致Glide的一些问题,Glide使用setTag存储了请求
*/
@Override
@Nullable
public Request getRequest() {
Object tag = getTag();
Request request = null;
if (tag != null) {
if (tag instanceof Request) {
request = (Request) tag;
} else {
throw new IllegalArgumentException(
"You must not call setTag() on a view Glide is targeting");
}
}
return request;
}
上面代码注释说的比较清楚,就是view会存储当前view的request。
好了,接着into方法跟进
> 代码片段18
private <Y extends Target<TranscodeType>> Y into(@NonNull Y target,@Nullable RequestListener<TranscodeType> targetListener,BaseRequestOptions<?> options,Executor callbackExecutor) {
//获取request
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//...略...
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
先看下buildRequest都做了什么工作,buildRequest方法内部会直接调用buildRequestRecursive
> 代码片段19
private Request buildRequestRecursive(Object requestLock,Target<TranscodeType> target,@Nullable RequestListener<TranscodeType> targetListener,@Nullable RequestCoordinator parentCoordinator,TransitionOptions<?, ? super TranscodeType> transitionOptions,Priority priority,int overrideWidth,int overrideHeight,BaseRequestOptions<?> requestOptions,Executor callbackExecutor) {
// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
Request mainRequest =
buildThumbnailRequestRecursive(
requestLock,
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
if (errorRequestCoordinator == null) {
return mainRequest;
}
int errorOverrideWidth = errorBuilder.getOverrideWidth();
int errorOverrideHeight = errorBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
Request errorRequest =
errorBuilder.buildRequestRecursive(
requestLock,
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder,
callbackExecutor);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
上面这个方法就会判断使用Glide的时候是否调用了方法builder.error(RequestBuilder<TranscodeType> errorBuilder)
,这个是用来处理当builder请求失败以后,是否继续执行errorBuilder中的请求的过程。我们demo中没有设置这个,所以可以忽略这段逻辑,直接返回了第9行处的调用,继续往下看
> 代码片段20
private Request buildThumbnailRequestRecursive(Object requestLock,Target<TranscodeType> target,RequestListener<TranscodeType> targetListener,@Nullable RequestCoordinator parentCoordinator,TransitionOptions<?, ? super TranscodeType> transitionOptions,Priority priority,int overrideWidth,int overrideHeight,BaseRequestOptions<?> requestOptions,Executor callbackExecutor) {
//略去与缩略图相关的请求设置
// Base case: no thumbnail.
return obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
上面代码逻辑中我们省略了和缩略图请求相关的逻辑,直接obtainRequest
方法。obtainRequest
这个方法就是通过调用SingleRequest
的obtain
的方法直接new了一个SingleRequest
对象,方法内部没有额外的逻辑,在此就不贴代码了。
返回到代码片段18
into方法中,request有了,接着往下走
//清除将要发生的加载过程释放资源
requestManager.clear(target);
//给当前view设置request,还记的前面讲的ViewTarget类里面的setTag和getTag方法吗,这里就会调用到,用以将request和view绑定
target.setRequest(request);
//追踪请求,其实就是开始加载数据
requestManager.track(target, request);
我们看下最后一句是怎么加载数据的
> 代码片段22 RequestManager.java
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
上面分析过这个target就是DrawableImageViewTarget
,而DrawableImageViewTarget继承自ImageViewTarget
,而ImageViewTarget间接实现了LifecycleListener
,并在onStart onStop方法中完成开启和停止动画的逻辑。
先看下targetTracker对象的类
public final class TargetTracker implements LifecycleListener {
private final Set<Target<?>> targets =
Collections.newSetFromMap(new WeakHashMap<Target<?>, Boolean>());
public void track(@NonNull Target<?> target) {
targets.add(target);
}
public void untrack(@NonNull Target<?> target) {
targets.remove(target);
}
@Override
public void onStart() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onStart();
}
}
@Override
public void onStop() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onStop();
}
}
@Override
public void onDestroy() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onDestroy();
}
}
//略
}
TargetTracker
类中维护着一个集合,保存了target,也就是用来展示图片的目标view。该类实现了LifecycleListener
接口,并在响应的回调中调用Target的回调方法,例如上面说到的ImageViewTarget
的回调去执行动画。
还记得上篇文章结尾讲到的RequestManager
的onStart和onStop
方法吗?这两个方法中都会执行targetTracker.onStart
和targetTracker.onStop
方法。这样RequestManagerFragment
的生命周期函数又和Target的生命周期绑定了。
再来总结下:上篇文章将到Glide创建的透明的Fragment的生命周期和RequestManager的生命周期绑定了,所以Fragment生命周期方法发生回调的时候,会调用RequestManager,而RequestManager的生命周期方法中会回调
TargetTracker
的生命周期方法,而TargetTracker
的生命周期方法会遍历内部set集合并调用集合元素Target的生命周期方法,而这个集合就是通过targetTracker.track(target);
方法添加的,集合元素Target的生命周期方法的内部会执行相应动画的开始和停止逻辑。
接下来看代码片段22
track方法的第二句代码,
//这里request是SingleRequest类的对象,上文已经分析过了
public void runRequest(@NonNull Request request) {
//将请求加入队列
requests.add(request);
if (!isPaused) {
//开始请求
request.begin();
} else {
//如果isPasued 就清除请求
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
//将请求加入pendingRequests队列
pendingRequests.add(request);
}
}
看SingleRequest
的begin方法法
public void begin() {
synchronized (requestLock) {
//略。。。
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
//注释5
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
//这里会设置target的placeholder
target.onLoadStarted(getPlaceholderDrawable());
}
//略。。。
}
}
这个方法省略判空抛异常的判断,修改status
,这个status
负责记录加载过程中的状态,第一个if判断了,如果Glide设置了overrideWidth
和overrideHeight
属性,也就是使用过程中调用了override
方法,就会进入判断并调用onSizeReady
方法,这个方法后面还会看到,这里先不讲。我们使用的时候没设置ovrride、所以看注释5
的 else逻辑调用target.getSize(this);
这个方法传递的参数是this,也就是SingleRequest
对象,这个对象实现了SizeReadyCallback
接口
com.bumptech.glide.request.target.ViewTarget.SizeDeterminer.java
void getSize(@NonNull SizeReadyCallback cb) {
int currentWidth = getTargetWidth();
int currentHeight = getTargetHeight();
//注释6
if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
cb.onSizeReady(currentWidth, currentHeight);
return;
}
// We want to notify callbacks in the order they were added and we only expect one or two
// callbacks to be added a time, so a List is a reasonable choice.
if (!cbs.contains(cb)) {
cbs.add(cb);
}
if (layoutListener == null) {
//如果目标view没有设置具体的宽高,就会给getViewTreeObserver设置一个监听
//此监听就是当onPreDraw系统方法回调的时候,去获取view的宽高
//获取到的话,回调SingleRequest的onSizeReady方法
ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
observer.addOnPreDrawListener(layoutListener);
}
}
target.getSize(this);
这代码中target是DrawableImageViewTarget
类型对象,而他又间接实现了ViewTarget
所以这里getSize其实就是ViewTarget
中的方法,然后会调用到ViewTarget
的内部类SizeDeterminer
中的getSize
方法,也就是上面这段代码,看下这段代码中注释6
处的判断,这里判断的是View的宽高是否合法,如果View的宽高设置的wrap_content,则这里获取的值为0,然后跳过判断往下走、否则进入判断中的逻辑。先说下宽高取值为0的情况,这种情况下会把SizeReadyCallback
对象,也就是前面传进来的SingleRequest对象添加到一个List集合cbs对象里,然后获取ViewTreeObserver
对象并给这个对象添加OnPreDrawListener监听,这个监听是在view树将要开始绘制之前触发的,有兴趣的可以跟进SizeDeterminerLayoutListener
类的onPreDraw
的方法看一下,这里的处理逻辑就是获取view宽高、然后遍历cbs集合,分别调用他们的onSizeReady
方法;而注释6
处的判断如果成立,则直接调用onSizeReady
方法
总结:SingleRequest
的onSizeReady
方法的调用会根据View的宽高,如果设置为wrapContent
,则onSizeReady
的调用会推迟到viewTree绘制之前,否则就会立即执行。归根结底都会执行SingleRequest
的onSizeReady
。
接着往下走,看onSizeReady方法
com.bumptech.glide.request.SingleRequest.java
public void onSizeReady(int width, int height) {
synchronized (requestLock) {
//修改状态
status = Status.RUNNING;
//获取剪裁乘数因子并据此修改宽高值
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
//加载数据
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);
}
}
代码中注释写的很清楚,接着往下看
com.bumptech.glide.load.engine.Engine.java
>代码片段23
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) {
//创建EngineKey,这个key是用来在内存中缓存Engine
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
//优先从内存加载图片 根据key寻找资源 这里的资源缓存在一个Map中value是EngineResource的弱引用
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);
}
}
//从内存中加载出资源了,执行回调
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
先来看一下loadFromMemory是如何从内存加载图片的
private EngineResource<?> loadFromMemory(EngineKey key, boolean isMemoryCacheable, long startTime) {
//如果禁止内存缓存就直接返回
if (!isMemoryCacheable) {
return null;
}
//首先从ActiveResources中获取
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
return active;
}
//从LruResourceCache中取,还记得前面讲new Glide那端代码吗?
//LruResourceCache这个对象就是在那里生成的
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
return cached;
}
return null;
}
//下面这三个方法是获取内存缓存的相关代码
@Nullable
private EngineResource<?> loadFromActiveResources(Key key) {
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
private EngineResource<?> loadFromCache(Key key) {
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
activeResources.activate(key, cached);
}
return cached;
}
private EngineResource<?> getEngineResourceFromCache(Key key) {
//cache 默认是LruResourceCache对象,是创建Engine对象时候作为参数传进来的,LruResourceCache继承自LruCache类
Resource<?> cached = cache.remove(key);
final EngineResource<?> result;
if (cached == null) {
result = null;
} else if (cached instanceof EngineResource) {
// Save an object allocation if we've cached an EngineResource (the typical case).
result = (EngineResource<?>) cached;
} else {
result =
new EngineResource<>(
cached, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
}
return result;
}
说一下这两种缓存方式,第一种ActiveResources是通过HashMap存储的是资源的弱引用,而第二中默认情况下是通过LruCache类中的cache对象(LinkedHashMap类型的数据结构)存储资源的,此cache初始容量100,负载因子0.75,采用的是LRU算法。这两种缓存方式都是内存缓存,面试的时候经常问到,这一点需要注意。
从内存加载图片的时候,先从activeResources
这里面去取数据,如果取到了直接返回,取不到就从cache
中去取数据,如果取到了,就将资源在activeResources
里面存一份,并返回。存的时候是先创建一个弱引用ResourceWeakReference类型的对象,这里有一点需要说明,创建弱引用对象的时候,会判断isMemoryCacheable
和isActiveResourceRetentionAllowed
的值,都为true的话,就会存资源,否则存一个null。这两个值,前者是使用glide的时候通过skipMemoryCache
方法设置,表示是跳过内存缓存,后者可以通过在自定义的AppGlideModule
类的applyOptions
方法中,通过调用builder.setIsActiveResourceRetentionAllowed(true);
来设置。将这个变量设置为true有可能会暂时增加应用程序的内存使用量。
回到代码片段23
,如果内存缓存没找到资源就接着调用waitForExistingOrStartNewJob
方法并返回。
com.bumptech.glide.load.engine.Engine.java
private <R> LoadStatus waitForExistingOrStartNewJob(
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,
EngineKey key,
long startTime) {
//注释7
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
return new LoadStatus(cb, current);
}
//负责通过添加和删除回调来管理一次加载过程,并且在加载完成的时候负责通知回调。实现了DecodeJob.Callback
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
//负责从缓存资源或者远程源文件中解码并转码的类,他实现了Runnable接口
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);
}
注释7中就是从Jobs
中根据key
查找缓存的engineJob
对象,至于Jobs
类就是管理engineJob
缓存的,它内部维护着两个hashmap
来存储engineJob
,至于用哪个map存,是根据开发者设置的onlyRetrieveFromCache
的true
或false
来决定的,这里笔者有点疑惑,感觉这两个map没区别,读者有想法的可以留言,解答笔者的疑惑。若果从缓存中获取到了engineJob
,就证明相同的请求工作已经存在了,所以不在需要了。执行if中的addCallback
逻辑。addCallback
代码如下,可以简单看一下
> 代码片段24
//参数说明 cb==就是SingleRequest对象,callbackExecutor就是调用into方法时创建Executors.mainThreadExecutor()、是主线程池
synchronized void addCallback(final ResourceCallback cb, Executor callbackExecutor) {
//注释8 这里注意下,后面会用到
//这里cbs是ResourceCallbacksAndExecutors类型,他的add方法会在他的成员变量
//List<ResourceCallbackAndExecutor> callbacksAndExecutors中,把add方法的两个参数
//封装成一个对象ResourceCallbackAndExecutor并添加进列表中。ResourceCallbackAndExecutor这个对象的cb变量就是参数cb,executor变量就是callbackExecutor参数
//这里的参数cb就是SingleRequest
//参数callbackExecutor 就是我们调用into方法中,系统帮我们创建的Executors.mainThreadExecutor() 他通过handler将子线程中的代码发往主线程执行
cbs.add(cb, callbackExecutor);
if (hasResource) {
// Acquire early so that the resource isn't recycled while the Runnable below is still sitting
// in the executors queue.
incrementPendingCallbacks(1);
//有资源、直接回调成功
callbackExecutor.execute(new CallResourceReady(cb));
} else if (hasLoadFailed) {
incrementPendingCallbacks(1);
//没有资源,调用失败
callbackExecutor.execute(new CallLoadFailed(cb));
} else {
Preconditions.checkArgument(!isCancelled, "Cannot add callbacks to a cancelled EngineJob");
}
}
接着看注释7
处,如果没有从缓存中取到engineJob
,就会创建一个,然后执行后面的engineJob.start(decodeJob);
代码
com.bumptech.glide.load.engine.EngineJob.java
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
//到这里之前一直都在主线程,下面这句代码就会切换到子线程
executor.execute(decodeJob);
}
com.bumptech.glide.load.engine.DecodeJob.java
boolean willDecodeFromCache() {
Stage firstStage = getNextStage(Stage.INITIALIZE);
return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}
//这个方法后面还会出现。根据
//Stage表示从哪里解码数据,或者当前解码阶段 。枚举类型,取值分别为
//1、INITIALIZE 初始化阶段
//2、RESOURCE_CACHE 从缓存的资源解码
//3、DATA_CACHE 从缓存的源数据解码。
//4、SOURCE 从网络加载
//5、ENCODE 加载成功后的编码阶段
//6、FINISHED 结束
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);
}
}
上面方法先获取executor对象,根据是否使用磁盘缓存来决定使用哪个executor。看下上面getNextStage
方法,根据传进来的参数Stage=INITIALIZE
,进入第一个case,成员变量diskCacheStrategy
就是使用Glide的时候设置的缓存策略,如果没传就用默认的AUTOMATIC策略。而他的decodeCachedResource
方法默认返回true,所以getNextStage
方法返回的是Stage.RESOURCE_CACHE
,进而willDecodeFromCache
方法返回的是true,所以获取到的executor对象就是diskCacheExecutor
。这里diskCacheExecutor就是代码片段4
中build方法里的第二个if判断中的变量,是一个GlideExecutor
对象,他内部代理的线程池是核心线程数和最大线程数都为1的ThreadPoolExecutor
对象,接着调用executor.execute(decodeJob);
代码,而且我们那知道decodeJob实现了Runnable接口,好了看下execute
方法
@Override
public void execute(@NonNull Runnable command) {
//
delegate.execute(command);
}
这不就是一个线程池执行线程的过程嘛~,然后线程执行,就会在子线程执行decodeJob
的run
方法,所以接下来进入子线程看看run
方法怎么执行的。但是在看run
方法之前,我们先看一下前面一个遗留的方法,前面创建Glide
对象的时候,我说过最终会走Glide
的构造方法,这个构造方法有一百多行,现在我们贴出部分代码
Glide(@NonNull Context context,@NonNull Engine engine,@NonNull MemoryCache memoryCache,@NonNull BitmapPool bitmapPool,@NonNull ArrayPool arrayPool,
@NonNull RequestManagerRetriever requestManagerRetriever,@NonNull ConnectivityMonitorFactory connectivityMonitorFactory,int logLevel,
@NonNull RequestOptionsFactory defaultRequestOptionsFactory,@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
@NonNull List<RequestListener<Object>> defaultRequestListeners,boolean isLoggingRequestOriginsEnabled,boolean isImageDecoderEnabledForBitmaps) {
//设置参数中传进来的成员变量 此处略....
//管理组件注册以扩展或替换Glide的默认加载,解码和编码逻辑,后面对调用大量的append方法
registry = new Registry();
registry.register(new DefaultImageHeaderParser());
///略。。。
registry
.append(int.class, InputStream.class, resourceLoaderStreamFactory)
.append(int.class, ParcelFileDescriptor.class, resourceLoaderFileDescriptorFactory)
.append(Integer.class, InputStream.class, resourceLoaderStreamFactory)
.append(Integer.class, ParcelFileDescriptor.class, resourceLoaderFileDescriptorFactory)
.append(Integer.class, Uri.class, resourceLoaderUriFactory)
.append(int.class, AssetFileDescriptor.class, resourceLoaderAssetFileDescriptorFactory)
.append(Integer.class, AssetFileDescriptor.class, resourceLoaderAssetFileDescriptorFactory)
.append(int.class, Uri.class, resourceLoaderUriFactory)
.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
.append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
.append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
.append(
String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
.append(Drawable.class, Drawable.class, new UnitDrawableDecoder())
/* 注册资源转码器 资源转码器可以从给定的资源类型(第一个参数)转换为给定的转码类型(第二个参数)。*/
.register(Bitmap.class, BitmapDrawable.class, new BitmapDrawableTranscoder(resources))
//略其他资源转码器
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
glideContext = new GlideContext(context,arrayPool,registry,imageViewTargetFactory,
defaultRequestOptionsFactory,defaultTransitionOptions,defaultRequestListeners,
engine,isLoggingRequestOriginsEnabled,logLevel);
}
看其中一个append
方法append(String.class, InputStream.class, new StringLoader.StreamFactory())
,append
方法三个参数,第一个表示数据源的类类型,第二个表示加载之后的数据的类类型,第三个表示ModelLoader
的工厂类,而ModelLoader<Model,Data>
就是其实就是将数据源(例如url,file)解析成图片数据(例如数据流)的管理接口。针对不同的数据源转换成不同的图片数据,有具体的类,他们都实现了ModelLoader
接口。上面构造方法中也看到了,有各种不同的Model
和data
类型的转换。而append
方法会将三个参数封装到一个Entry<Model,Data>
对象中,然后缓存到MultiModelLoaderFactory
对象的一个entry
的list
中。
好了,本篇文章先讲到这里,本篇文章中我们讲到了Glide的三级缓存中的第一级内存缓存,本篇文章中的代码也都是运行在主线程,下一篇文章我们就将进入子线程看看数据真正的加载逻辑以及加载完成后的缓存和显示逻辑。