文章目录
Glide源码分析
前言
本文分析基于Glide 4.10.0,若有错误疏漏之处,请各位大佬指正。
基本使用
Glide.with(this).load(strUrl).into(imageView);
with(Context context)方法
Glide中的这些with的构造方法会绑定传入对象的生命周期,但是为什么要这么做呢?
因为退出一个页面时,如果此时还在加载图片,就可能会发生内存泄漏,所以就需要Glide在退出页面时取消加载请求,防止内存泄漏。
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getContext()).get(fragment);
}
@NonNull
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
可以看到,这些方法都是通过Glide的内的静态方法getRetriever(Context context)获取到RequestManagerRetriever,再返回它的get方法返回的RequestManager对象。
getRetriever(Context context):
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
Preconditions.checkNotNull( //判断了传入的Context对象是否为null,如果为null就会抛出异常
context,
"You cannot start a load on a not yet attached View or a Fragment where getActivity() "
+ "returns null (which usually occurs when getActivity() is called before the Fragment "
+ "is attached or after the Fragment is destroyed).");
return Glide.get(context).getRequestManagerRetriever();
}
//可以看到,这个get方法通过双重校验锁来获取类的单例对象。
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context, annotationGeneratedModule); //初始化并创建Glide对象
}
}
}
return glide;
}
//checkAndInitializeGlide会调用initializeGlide的构造方法,其中有下面这样一行代码来构建Glide对象
Glide glide = builder.build(applicationContext);
//Glide.build方法
Glide build(@NonNull Context context) {
...
if (memoryCache == null) { //创建内存缓存,它的实现是Lru算法,Lru缓存下文还会说道
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
if (diskCacheFactory == null) { //创建磁盘缓存,和内存缓存的存储一样,都是使用LinkedHashMap来实现Lru算法
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
...
//通过Glide的构造方法来创建Glide对象
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled,
isImageDecoderEnabledForBitmaps,
hardwareBitmapFdLimit,
minHardwareDimension);
}
public RequestManagerRetriever getRequestManagerRetriever() {
return requestManagerRetriever; //直接返回了Glide的成员变量requestManagerRetriever
}
RequestManagerRetriever.get(Context context)
//可以看到下面的get方法,如果在主线程并且context不是Application的实例,就会根据传入的Context对象是否是FragmentActivity,Activity或ContextWrapper的实例,调用不同的get的构造方法来获取RequestManager;否则调用getApplicationManager方法
public RequestManager get(@NonNull Context context) {
if (context == null) { //context为null直接抛出异常
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) { //当前在主线程,并且传入的context对象不是Application的实例
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper
// Only unwrap a ContextWrapper if the baseContext has a non-null application context.
// Context#createPackageContext may return a Context without an Application instance,
// in which case a ContextWrapper may be used to attach one.
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
//下面也是通过双重校验锁来获取RequestManager单例。
private RequestManager getApplicationManager(@NonNull Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
// Normally pause/resume is taken care of by the fragment we add to the fragment or
// activity. However, in this case since the manager attached to the application will not
// receive lifecycle events, we must force the manager to start resumed using
// ApplicationLifecycle.
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
//上面RequestManagerRetriever.get方法中调用的几个get方法都是类似的,下面就传入FragmentActivity实例时的get方法来分析:
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) { //如果不在主线程,又会调用RequestManagerRetriever.get方法,然后还是会调用getApplicationManager返回RequestManager单例
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity); //如果安卓版本>=17(安卓4.2)并且activity已经销毁,就抛出异常
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); //通过这个方法获取RequestManager对象
}
}
/**
这个方法会先获取或创建SupportRequestManagerFragment,然后在当前的activity中添加一个没有页面的Fragment,以此将这个Fragment的生命周期和当前activity关联起来,当退出页面时,这个Fragment也会销毁
*/
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible); //获取SupportRequestManagerFragment对象
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingSupportRequestManagerFragments.put(fm, current);
//下面将current这个没有页面的Fragment对象添加到当前页面中
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
小结
Glide.with方法的主要作用就是:
在当前页面添加一个没有布局的fragment,以此和当前页面的生命周期关联起来,因此这个fragment中引用的RequestManager会在页面退出时收到消息并停止加载。
如果传入的是Application或其他没有生命周期的对象,创建(获取)并返回RequestManager对象,它和应用的生命周期相关联
RequestManager.load方法
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
//asDrawable方法的作用就是创建了一个RequestBuilder对象
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
//RequestBuilder.load(string)
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
//这个方法将接受到的String字符串url向上转型为Object,并将它赋给了成员变量model
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
小结
load方法的作用是返回一个RequestBuilder对象,用于后面into方法使用给定的model来进行加载。
RequestBuilder.into(image)
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread(); //必须在主线程中,否则抛出异常
Preconditions.checkNotNull(view); //传入的Imageview不能为null,否则抛出异常
//BaseRequestOptions中存储了一些请求时的参数,如请求优先级,是否缓存等
BaseRequestOptions<?> requestOptions = this; //RequestBuilder是BaseRequestOptions的子类,所以这里直接通过父类引用指向子类实例对象
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don't retain the transformation applied based on the previous
// View's scale type.
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
//没有给传入的Imageview设置缩放类型,就会调用下面的这个into方法,下面还会分析这个方法
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
//GlideContext.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) {
//根据传入的不同的Class对象构建不同的ViewTarget对象,通常会构建DrawableImageViewTarget对象
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)");
}
}
}
//这个into方法下面会详细分析
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) { //上面在load方法中会存储传入的model,同时这个标记位就会置为true
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request request = buildRequest(target, targetListener, options, callbackExecutor); //构建Request对象
Request previous = target.getRequest();
if (request.isEquivalentTo(previous) //如果前后两个请求有相同的options参数和大小,并且options可以被缓存或前一个请求还未完成,那么就让前一个请求继续运行
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
// 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); //给Target设置Request
requestManager.track(target, request); //这个方法中会执行传入上面构建的Request对象
return target;
}
buildRequest:构建请求的方法
下面会一直追溯到最终构建Request接口实例的方法,其他无关的代码会进行忽略
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
/*requestLock=*/ new Object(),
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
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) {
...
Request mainRequest =
buildThumbnailRequestRecursive(
requestLock,
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
...
}
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) {
if (thumbnailBuilder != null) {
...
ThumbnailRequestCoordinator coordinator =
new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
Request fullRequest =
obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
...
}
}
private Request obtainRequest(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
//SingleRequest是Request接口的实现类
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
public static <R> SingleRequest<R> obtain(
Context context,
GlideContext glideContext,
Object requestLock,
Object model,
Class<R> transcodeClass,
BaseRequestOptions<?> requestOptions,
int overrideWidth,
int overrideHeight,
Priority priority,
Target<R> target,
RequestListener<R> targetListener,
@Nullable List<RequestListener<R>> requestListeners,
RequestCoordinator requestCoordinator,
Engine engine,
TransitionFactory<? super R> animationFactory,
Executor callbackExecutor) {
//下面调用了它的构造方法来创建一个Request对象
return new SingleRequest<>(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
engine,
animationFactory,
callbackExecutor);
}
//调用终于到底了,哇,有亿点激动
//可以看到,这个构造方法将一系列参数赋给了SingleRequest来做初始化操作
private SingleRequest(
Context context,
GlideContext glideContext,
@NonNull Object requestLock,
@Nullable Object model,
Class<R> transcodeClass,
BaseRequestOptions<?> requestOptions,
int overrideWidth,
int overrideHeight,
Priority priority,
Target<R> target,
@Nullable RequestListener<R> targetListener,
@Nullable List<RequestListener<R>> requestListeners,
RequestCoordinator requestCoordinator,
Engine engine,
TransitionFactory<? super R> animationFactory,
Executor callbackExecutor) {
this.requestLock = requestLock;
this.context = context;
this.glideContext = glideContext;
this.model = model;
this.transcodeClass = transcodeClass;
this.requestOptions = requestOptions;
this.overrideWidth = overrideWidth;
this.overrideHeight = overrideHeight;
this.priority = priority;
this.target = target;
this.targetListener = targetListener;
this.requestListeners = requestListeners;
this.requestCoordinator = requestCoordinator;
this.engine = engine;
this.animationFactory = animationFactory;
this.callbackExecutor = callbackExecutor;
status = Status.PENDING;
if (requestOrigin == null && glideContext.isLoggingRequestOriginsEnabled()) {
requestOrigin = new RuntimeException("Glide request origin trace");
}
}
创建完了Request对象,当然要来执行了,下面深入RequestManager.track方法中一探究竟
//上面的RequestBuilder.into方法
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);
...
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request); //前面提到,这个方法内会执行Request
return target;
}
//RequestManager.track方法
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request); //一看就是执行请求的方法,进去看看
}
//RequestTracker.runRequest方法
public void runRequest(@NonNull Request request) {
requests.add(request); //requests是一个Set
if (!isPaused) { //如果没有暂停,就开始请求
request.begin(); //调用Request接口的begin方法
} else {
request.clear(); //这个方法会让当前请求释放它持有的所有资源,如果设置了占位符就会将它显示,还会标记这个请求为取消状态
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request); //加入到待执行请求列表中
}
}
上面提到过,Request接口的实现类是SingleRequest,所以下面看看begin方法的具体实现:
SingleRequest.begin()
@Override
public void begin() {
synchronized (requestLock) {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) { //如果load方法传入的参数(String,Url等)为null,就会加载失败并抛出异常
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)) { //如果通过override方法指定了宽高,就直接调用onSizeReady方法
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this); //没有通过override方法指定宽高就会通过getSize方法测量Imageview的宽高,然后还是会调用onSizeReady方法
}
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));
}
}
}
@Override
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (IS_VERBOSE_LOGGABLE) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadStatus =
engine.load( //调用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);
// This is a hack that's only useful for testing right now where loads complete synchronously
// even though under any executor running on any thread but the main thread, the load would
// have completed asynchronously.
if (status != Status.RUNNING) {
loadStatus = null;
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
}
咳咳,重点来了,下面这个Engine中的load方法中就开始真正去执行加载的逻辑了。这个方法的注释描述了加载的大致逻辑,大意如下:
/**
根据给定的参数开始加载
必须在主线程中调用
下面是请求的具体流程:
1.检查当前积极使用的资源的集合,如果存在就将它返回,并且将任何新的非活动的资源移动到内存缓存。
2.检查内存缓存,返回存在的缓存资源。
3.检查当前正在进行加载的集合并且将callback添加到正在进行中的加载(如果存在)。
4.启动一个新的加载。
活动资源(对应ActiveResources类)用来缓存正在被使用的图片资源,这些图片资源存储在ActiveResources的一个Hashmap中,这个Hashmap定义如下:
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
*/
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;
//EngineKey是一个数据结构,存储了请求的一些基本信息,每个key对应一个图片资源,只有下面这8个参数全部相同equals方法才会判断是同一个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);
return null;
}
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> active = loadFromActiveResources(key); //第一步,通过传入的图片标识key先从ActiveResources的Hashmap中加载
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return active;
}
EngineResource<?> cached = loadFromCache(key); //第二步,根据key从内存缓存中加载
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
}
return null;
}
//顾名思义,等待正在进行的加载或开启一个新的加载
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) {
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) { //如果已经将任务已经加入到jobs中的HashMap中,并且请求还未完成(即还未从HashMap中移除),就不会再创建新的加载任务。
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 = //直接将上面的enginejob封装到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);
}
public synchronized void start(DecodeJob<R> decodeJob) { //这个DecodeJob是一个Runnable的子类,所以可以在线程池中运行。其中会进行网络请求获取图片数据并进行解码。
this.decodeJob = decodeJob;
//可以看到下面会根据是否设置磁盘缓存返回相应的线程池加载器来开启加载任务。顺便提一点,因为从磁盘中检索是否有缓存比较耗时,所以要在子线程中加载。
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
//DecodeJob.run(),这个runWrapped方法就开始在子线程中执行了
@Override
public void run() {
...
runWrapped();
}
private void runWrapped() {
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);
}
}
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) { //这个while循环不断执行下一个任务,startNext方法为执行下一个任务的方法
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
}
//DataCacheGenerator.startNext()
@Override
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
Key sourceId = cacheKeys.get(sourceIdIndex);
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
/*
先从DiskLruCache中获取磁盘缓存,这个get方法最终会调用到DiskLruCache的get方法获取磁盘缓存。
下面是DiskLruCache实现Lru所用的LinkedHashMap的定义:
private final LinkedHashMap<String, Entry> lruEntries =
new LinkedHashMap<String, Entry>(0, 0.75f, true);
*/
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); //loadData方法会调用到HttpUrlFetcher的loadData方法实现来进行网络请求获取图片
}
}
return started;
}
runGenerators()这个方法中会执行网络请求获取图片数据,获取后会进行解码操作,解码完成后会通过回调通知主线程加载任务完成(这是相较于老版本的区别,老版本通过Handler来通知主线程的)
在DecodeJob解码完成后,会回调回调接口的onResourceReady方法,它的实现是EngineJob,所以会回调它的这个方法。其中又会回调到Engine中的onEngineJobComplete方法,它的实现如下:
@Override
public synchronized void onEngineJobComplete(
EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
// A null resource indicates that the load failed, usually due to an exception.
if (resource != null && resource.isMemoryCacheable()) {
activeResources.activate(key, resource); //将获取并解码的图片资源放到activeResources中的弱引用HashMap中
}
jobs.removeIfCurrent(key, engineJob);
}
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();
}
}
Lru缓存的具体实现:
EngineResource中有一个整形变量acquire,用来记录一个EngineResource(它作为弱引用存放在ActiveResources中的弱引用HashMap中)被引用的次数,当它被一个使用者使用时,acquire会加一,表示又多了一个使用者;反之acquire会减一,当acquire == 0时会将它加入到LruCache的LinkedHashMap中。
两个方法的实现如下:
synchronized void acquire() {
if (isRecycled) {
throw new IllegalStateException("Cannot acquire a recycled resource");
}
++acquired;
}
void release() {
boolean release = false;
synchronized (this) {
if (acquired <= 0) {
throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
}
if (--acquired == 0) { //acquire为0就会回调下面的方法,将资源加入
release = true;
}
}
if (release) {
listener.onResourceReleased(key, this);
}
}
//Engine.onResourceReleased方法
@Override
public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
activeResources.deactivate(cacheKey);
if (resource.isMemoryCacheable()) {
cache.put(cacheKey, resource); //将资源加入到LruCache的LinkedHashMap中
} else {
resourceRecycler.recycle(resource);
}
}
Glide三级缓存
可以从Engine中load方法的加载过程看到,4.10.0的Glide缓存策略和以前的版本只有一点顺序上的小小区别:
弱引用中缓存中加载 --> LruCache中加载 --> 磁盘缓存中加载
-
先从弱引用Hashmap缓存加载。
这个Hashmap在ActiveResources类中的定义如下:
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>(); -
再从LruCache中加载
关于LruCache这里可以说道说道,操作系统中换页算法中Lru换页算法与此类似。
LruCache
Lru即least recently used,最近最少使用算法。安卓中有对应的同名类LruCache,Glide就使用了它来缓存图片资源。其中维护了一个LinkedHashMap来存取数据,它的底层实现是数组 + 双向链表。其中put方法存储数据时,当链表中的结点数达到最大数量时,会将最近最少使用的节点移除,避免图片资源占用过大。
LinkedHashMap
它是HashMap的子类,和HashMap的区别就是它会通过双向链表记录访问或插入节点的顺序,在访问节点时,会更新该节点的前后指针,将它调整到链表表尾,所以它是实现Lru算法很好的数据结构。也就是说,最近访问的节点是表尾节点,最近最少访问的节点是表头结点。
-
从DiskLruCache中检索缓存或新建网络请求
上面也分析过,磁盘缓存的实现也是LinkedHashMap;网络请求就不再多说了。
下面这张图是以前版本的缓存流程,只是一二级缓存顺序交换了而已。