public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
}
ActivityFragmentLifecycle.class中持有一个lifecycleListeners,在Fragment进入关键生命周期时Lifecycle会通知他的所有Listener
class ActivityFragmentLifecycle implements Lifecycle {
…
private final Set lifecycleListeners;void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
void onStop() {
isStarted = false;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}
void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
…
}
RequestManger.class关键生命周期中处理加载任务
@Override
public void onStart() {
resumeRequests();
targetTracker.onStart();
}
@Override
public void onStop() {
pauseRequests();
targetTracker.onStop();
}
@Override
public void onDestroy() {
targetTracker.onDestroy();
for (Target<?> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();
requestTracker.clearRequests();
}
1.3、总结
- Glide在加载绑定了Activity的生命周期。
- 在Activity内新建一个无UI的Fragment,这个特殊的Fragment持有一个Lifecycle。通过Lifecycle在Fragment关键生命周期通知RequestManger进行相关的操作。
- 在生命周期onStart时继续加载,onStop时暂停加载,onDestory是停止加载任务和清除操作。
1.4、面试
Glide为什么不能在子线程中with?
子线程中不会去添加 生命周期管理机制,主线程才会添加一个 空白的Fragment去监听 Activity Fragment的变化。
每一个with()方法重载的代码都非常简单,都是调用调用getRetriever(activity).get(activity)
,返回一个RequestManager对象。
getRetriever(…).get(…)做了什么事情?
不论传入Activity、FragmentActivity、Fragment最终都会调用
supportFragmentGet()
方法,而这两个方法最终流程都是一致的就是那就是会向当前的Activity当中添加一个隐藏的Fragment。
那么这里为什么要添加一个隐藏的Fragment呢?
答:因为Glide需要知道加载的生命周期。很简单的一个道理,如果你在某个Activity上正在加载着一张图片,结果图片还没加载出来,这时候Activity被用户关掉了,那么图片就应该取消加载,可是Glide并不知道Activity的生命周期,怎么办呢? 于是Glide就使用了添加隐藏Fragment的这种小技巧,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止图片加载了。
既然有了Application,为什么不用registerActivityLifecycleCallbacks而是用隐藏的Fragment?
registerActivityLifecycleCallbacks是可以实现,并且我的小伙伴在自己的某些工程中也在使用,但是个人理解是这样的: registerActivityLifecycleCallbacks监控所有的Activity生命周期,然而当你使用Glide加载图片时,并不是所有的Activity都会用到Glide加载图片(大多数情况),所以呢,使用registerActivityLifecycleCallbacks存在资源浪费的现象。不仅如此,你监控了所有的activity怎么和Glide想要监控的Activity关联到一块去,虽然可以实现,但是这个办法真心不实用,既然Glide给了我们这么完美的解决方案我们就要学以致用,以后尽力用到自己的工程中去。
2、load()
2.2、源码
由于with()方法返回的是一个RequestManager对象,那么很容易就能想到,load()方法是在RequestManager类当中的,所以说我们首先要看的就是RequestManager这个类。不过在上一篇文章中我们学过,Glide是支持图片URL字符串、图片本地路径等等加载形式的,因此RequestManager中也有很多个load()方法的重载。但是这里我们不可能把每个load()方法的重载都看一遍,因此我们就只选其中一个加载图片URL字符串的load()方法来进行研究吧。
public class RequestManager implements LifecycleListener {
// 那么我们先来看load()方法,这个方法中的逻辑是非常简单的,只有一行代码,
// 就是先调用了fromString()方法,再调用load()方法,然后把传入的图片URL地址传进去。
// 而fromString()方法也极为简单,就是调用了loadGeneric()方法,并且指定参数为String.class,因为load()方法传入的是一个字符串参数。那么看上去,好像主要的工作都是在loadGeneric()方法中进行的了。
public DrawableTypeRequest load(String string) {
return (DrawableTypeRequest) fromString().load(string);
}
public DrawableTypeRequest fromString() {
return loadGeneric(String.class);
}
// 其实loadGeneric()方法也没几行代码,这里分别调用了Glide.buildStreamModelLoader()方法和Glide.buildFileDescriptorModelLoader()方法来获得ModelLoader对象。
// ModelLoader对象是用于加载图片的,而我们给load()方法传入不同类型的参数,这里也会得到不同的ModelLoader对象。
// 由于我们刚才传入的参数是String.class,因此最终得到的是StreamStringLoader对象,它是实现了ModelLoader接口的。
private DrawableTypeRequest loadGeneric(Class modelClass) {
ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
Glide.buildFileDescriptorModelLoader(modelClass, context);
if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
throw new IllegalArgumentException("Unknown type " + modelClass + “. You must provide a Model of a type for”
- " which there is a registered ModelLoader, if you are using a custom model, you must first call"
- " Glide#register with a ModelLoaderFactory for your custom model class");
}
// loadGeneric()方法是要返回一个DrawableTypeRequest对象的,
// 因此在loadGeneric()方法的最后又去new了一个DrawableTypeRequest对象,
// 然后把刚才获得的ModelLoader对象,还有一大堆杂七杂八的东西都传了进去。具体每个参数的含义和作用就不解释了,我们只看主线流程。
return optionsApplier.apply(
new DrawableTypeRequest(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
}
}
那么这个DrawableTypeRequest的作用是什么呢?我们来看下它的源码,如下所示:
public class DrawableTypeRequest extends DrawableRequestBuilder implements DownloadOptions {
private final ModelLoader<ModelType, InputStream> streamModelLoader;
private final ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader;
private final RequestManager.OptionsApplier optionsApplier;
private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
ModelLoader<A, InputStream> streamModelLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class resourceClass,
Class transcodedClass,
ResourceTranscoder<Z, R> transcoder) {
if (streamModelLoader == null && fileDescriptorModelLoader == null) {
return null;
}
if (transcoder == null) {
transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
}
DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
resourceClass);
ImageVideoModelLoader modelLoader = new ImageVideoModelLoader(streamModelLoader,
fileDescriptorModelLoader);
return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
}
DrawableTypeRequest(Class modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
super(context, modelClass,
buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
GlideDrawable.class, null),
glide, requestTracker, lifecycle);
this.streamModelLoader = streamModelLoader;
this.fileDescriptorModelLoader = fileDescriptorModelLoader;
this.optionsApplier = optionsApplier;
}
/**
- 最主要的就是它提供了asBitmap()和asGif()这两个方法。这两个方法我们在上一篇文章当中都是学过的,分别是用于强制指定加载静态图片和动态图片。而从源码中可以看出,它们分别又创建了一个BitmapTypeRequest和GifTypeRequest,如果没有进行强制指定的话,那默认就是使用DrawableTypeRequest。
*/
public BitmapTypeRequest asBitmap() {
return optionsApplier.apply(new BitmapTypeRequest(this, streamModelLoader,
fileDescriptorModelLoader, optionsApplier));
}
/**
*
*/
public GifTypeRequest asGif() {
return optionsApplier.apply(new GifTypeRequest(this, streamModelLoader, optionsApplier));
}
…
}
这个类中的代码本身就不多,我只是稍微做了一点简化。可以看到,最主要的就是它提供了asBitmap()和asGif()这两个方法。这两个方法我们在上一篇文章当中都是学过的,分别是用于强制指定加载静态图片和动态图片。而从源码中可以看出,它们分别又创建了一个BitmapTypeRequest和GifTypeRequest,如果没有进行强制指定的话,那默认就是使用DrawableTypeRequest。
好的,那么我们再回到RequestManager的load()方法中。刚才已经分析过了,fromString()方法会返回一个DrawableTypeRequest对象,接下来会调用这个对象的load()方法,把图片的URL地址传进去。但是我们刚才看到了,DrawableTypeRequest中并没有load()方法,那么很容易就能猜想到,load()方法是在父类当中的。
DrawableTypeRequest的父类是DrawableRequestBuilder,我们来看下这个类的源码:
public class DrawableRequestBuilder
extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
implements BitmapOptions, DrawableOptions {
DrawableRequestBuilder(Context context, Class modelClass,
LoadProvider<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> loadProvider, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle) {
super(context, modelClass, loadProvider, GlideDrawable.class, glide, requestTracker, lifecycle);
// Default to animating.
crossFade();
}
public DrawableRequestBuilder thumbnail(
DrawableRequestBuilder<?> thumbnailRequest) {
super.thumbnail(thumbnailRequest);
return this;
}
@Override
public DrawableRequestBuilder thumbnail(
GenericRequestBuilder<?, ?, ?, GlideDrawable> thumbnailRequest) {
super.thumbnail(thumbnailRequest);
return this;
}
@Override
public DrawableRequestBuilder thumbnail(float sizeMultiplier) {
super.thumbnail(sizeMultiplier);
return this;
}
@Override
public DrawableRequestBuilder sizeMultiplier(float sizeMultiplier) {
super.sizeMultiplier(sizeMultiplier);
return this;
}
@Override
public DrawableRequestBuilder decoder(ResourceDecoder<ImageVideoWrapper, GifBitmapWrapper> decoder) {
super.decoder(decoder);
return this;
}
@Override
public DrawableRequestBuilder cacheDecoder(ResourceDecoder<File, GifBitmapWrapper> cacheDecoder) {
super.cacheDecoder(cacheDecoder);
return this;
}
@Override
public DrawableRequestBuilder encoder(ResourceEncoder encoder) {
super.encoder(encoder);
return this;
}
@Override
public DrawableRequestBuilder priority(Priority priority) {
super.priority(priority);
return this;
}
public DrawableRequestBuilder transform(BitmapTransformation… transformations) {
return bitmapTransform(transformations);
}
public DrawableRequestBuilder centerCrop() {
return transform(glide.getDrawableCenterCrop());
}
public DrawableRequestBuilder fitCenter() {
return transform(glide.getDrawableFitCenter());
}
public DrawableRequestBuilder bitmapTransform(Transformation… bitmapTransformations) {
GifBitmapWrapperTransformation[] transformations =
new GifBitmapWrapperTransformation[bitmapTransformations.length];
for (int i = 0; i < bitmapTransformations.length; i++) {
transformations[i] = new GifBitmapWrapperTransformation(glide.getBitmapPool(), bitmapTransformations[i]);
}
return transform(transformations);
}
@Override
public DrawableRequestBuilder transform(Transformation… transformation) {
super.transform(transformation);
return this;
}
@Override
public DrawableRequestBuilder transcoder(
ResourceTranscoder<GifBitmapWrapper, GlideDrawable> transcoder) {
super.transcoder(transcoder);
return this;
}
public final DrawableRequestBuilder crossFade() {
super.animate(new DrawableCrossFadeFactory());
return this;
}
public DrawableRequestBuilder crossFade(int duration) {
super.animate(new DrawableCrossFadeFactory(duration));
return this;
}
public DrawableRequestBuilder crossFade(int animationId, int duration) {
super.animate(new DrawableCrossFadeFactory(context, animationId,
duration));
return this;
}
@Override
public DrawableRequestBuilder dontAnimate() {
super.dontAnimate();
return this;
}
@Override
public DrawableRequestBuilder animate(ViewPropertyAnimation.Animator animator) {
super.animate(animator);
return this;
}
@Override
public DrawableRequestBuilder animate(int animationId) {
super.animate(animationId);
return this;
}
@Override
public DrawableRequestBuilder placeholder(int resourceId) {
super.placeholder(resourceId);
return this;
}
@Override
public DrawableRequestBuilder placeholder(Drawable drawable) {
super.placeholder(drawable);
return this;
}
@Override
public DrawableRequestBuilder fallback(Drawable drawable) {
super.fallback(drawable);
return this;
}
@Override
public DrawableRequestBuilder fallback(int resourceId) {
super.fallback(resourceId);
return this;
}
@Override
public DrawableRequestBuilder error(int resourceId) {
super.error(resourceId);
return this;
}
@Override
public DrawableRequestBuilder error(Drawable drawable) {
super.error(drawable);
return this;
}
@Override
public DrawableRequestBuilder listener(
RequestListener<? super ModelType, GlideDrawable> requestListener) {
super.listener(requestListener);
return this;
}
@Override
public DrawableRequestBuilder diskCacheStrategy(DiskCacheStrategy strategy) {
super.diskCacheStrategy(strategy);
return this;
}
@Override
public DrawableRequestBuilder skipMemoryCache(boolean skip) {
super.skipMemoryCache(skip);
return this;
}
@Override
public DrawableRequestBuilder override(int width, int height) {
super.override(width, height);
return this;
}
@Override
public DrawableRequestBuilder sourceEncoder(Encoder sourceEncoder) {
super.sourceEncoder(sourceEncoder);
return this;
}
@Override
public DrawableRequestBuilder dontTransform() {
super.dontTransform();
return this;
}
@Override
public DrawableRequestBuilder signature(Key signature) {
super.signature(signature);
return this;
}
@Override
public DrawableRequestBuilder load(ModelType model) {
super.load(model);
return this;
}
@Override
public DrawableRequestBuilder clone() {
return (DrawableRequestBuilder) super.clone();
}
@Override
public Target into(ImageView view) {
return super.into(view);
}
@Override
void applyFitCenter() {
fitCenter();
}
@Override
void applyCenterCrop() {
centerCrop();
}
}
DrawableRequestBuilder中有很多个方法,这些方法其实就是Glide绝大多数的API了。里面有不少我们在上篇文章中已经用过了,比如说placeholder()方法、error()方法、diskCacheStrategy()方法、override()方法等。当然还有很多暂时还没用到的API,我们会在后面的文章当中学习。
到这里,第二步load()方法也就分析结束了。为什么呢?因为你会发现DrawableRequestBuilder类中有一个into()方法(上述代码第220行),也就是说,最终load()方法返回的其实就是一个DrawableTypeRequest对象。那么接下来我们就要进行第三步了,分析into()方法中的逻辑。
2.3、总结
load方法最终做的就是进行一些初始化的操作,获得了一个DrawableTypeRequest对象,通过这个对象我们就可以获得图片请求的request,然后再接下来的into方法中使用。
3、into()
3.1、详解
如果说前面两步都是在准备开胃小菜的话,那么现在终于要进入主菜了,因为into()方法也是整个Glide图片加载流程中逻辑最复杂的地方。
不过从刚才的代码来看,into()方法中并没有任何逻辑,只有一句super.into(view)。那么很显然,into()方法的具体逻辑都是在DrawableRequestBuilder的父类当中了。
3.1、源码
DrawableRequestBuilder的父类是GenericRequestBuilder,我们来看一下GenericRequestBuilder类中的into()方法,如下所示:
public Target into(ImageView view) {
Util.assertMainThread();
if (view == null) {
throw new IllegalArgumentException(“You must pass in a non null View”);
}
if (!isTransformationSet && view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
applyFitCenter();
break;
//
C
A
S
E
S
−
O
M
I
T
T
E
D
CASES-OMITTED
CASES−OMITTED
default:
// Do nothing.
}
}
return into(glide.buildImageViewTarget(view, transcodeClass));
}
这里前面一大堆的判断逻辑我们都可以先不用管,等到后面文章讲transform的时候会再进行解释,现在我们只需要关注最后一行代码。最后一行代码先是调用了glide.buildImageViewTarget()方法,这个方法会构建出一个Target对象,Target对象则是用来最终展示图片用的,如果我们跟进去的话会看到如下代码:
Target buildImageViewTarget(ImageView imageView, Class transcodedClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}
这里其实又是调用了ImageViewTargetFactory的buildTarget()方法,我们继续跟进去,代码如下所示:
public class ImageViewTargetFactory {
@SuppressWarnings(“unchecked”)
public Target buildTarget(ImageView view, Class clazz) {
if (GlideDrawable.class.isAssignableFrom(clazz)) {
return (Target) new GlideDrawableImageViewTarget(view);
} else if (Bitmap.class.equals(clazz)) {
return (Target) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (Target) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException("Unhandled class: " + clazz
- “, try .as*(Class).transcode(ResourceTranscoder)”);
}
}
}
可以看到,在buildTarget()
方法中会根据传入的class参数来构建不同的Target对象。那如果你要分析这个class参数是从哪儿传过来的,这可有得你分析了,简单起见我直接帮大家梳理清楚。这个class参数其实基本上只有两种情况,如果你在使用Glide加载图片的时候调用了asBitmap()方法,那么这里就会构建出BitmapImageViewTarget对象,否则的话构建的都是GlideDrawableImageViewTarget对象。至于上述代码中的DrawableImageViewTarget
对象,这个通常都是用不到的,我们可以暂时不用管它。
也就是说,通过glide.buildImageViewTarget()
方法,我们构建出了一个GlideDrawableImageViewTarget
对象。那现在回到刚才into()方法的最后一行,可以看到,这里又将这个参数传入到了GenericRequestBuilder
另一个接收Target对象的into()方法当中了。我们来看一下这个into()方法的源码:
public <Y extends Target> Y into(Y target) {
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException(“You must pass in a non null Target”);
}
if (!isModelSet) {
throw new IllegalArgumentException(“You must first set a model (try #load())”);
}
Request previous = target.getRequest();
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
// 重点:Request是用来发出加载图片请求的,它是Glide中非常关键的一个组件。
requestTracker.runRequest(request);
return target;
}
这里我们还是只抓核心代码,其实只有两行是最关键的,第15行调用buildRequest()方法构建出了一个Request对象,还有第18行来执行这个Request。
Request是用来发出加载图片请求的,它是Glide中非常关键的一个组件。我们先来看buildRequest()方法是如何构建Request对象的:
private Request buildRequest(Target target) {
if (priority == null) {
priority = Priority.NORMAL;
}
return buildRequestRecursive(target, null);
}
// buildRequest()方法的内部其实又调用了buildRequestRecursive()方法
private Request buildRequestRecursive(Target target, ThumbnailRequestCoordinator parentCoordinator) {
if (thumbnailRequestBuilder != null) {
if (isThumbnailBuilt) {
throw new IllegalStateException("You cannot use a request as both the main request and a thumbnail, "
- “consider using clone() on the request(s) passed to thumbnail()”);
}
// Recursive case: contains a potentially recursive thumbnail request builder.
if (thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) {
thumbnailRequestBuilder.animationFactory = animationFactory;
}
if (thumbnailRequestBuilder.priority == null) {
thumbnailRequestBuilder.priority = getThumbnailPriority();
}
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !Util.isValidDimensions(thumbnailRequestBuilder.overrideWidth,
thumbnailRequestBuilder.overrideHeight)) {
thumbnailRequestBuilder.override(overrideWidth, overrideHeight);
}
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
// Guard against infinite recursion.
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
Request thumbRequest = thumbnailRequestBuilder.buildRequestRecursive(target, coordinator);
isThumbnailBuilt = false;
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
// Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
Request thumbnailRequest = obtainRequest(target, thumbSizeMultiplier, getThumbnailPriority(), coordinator);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// Base case: no thumbnail.‘’
// 这里调用了obtainRequest()方法来获取一个Request对象,而obtainRequest()方法中又去调用了GenericRequest的obtain()方法。
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
}
private Request obtainRequest(Target target, float sizeMultiplier, Priority priority,
RequestCoordinator requestCoordinator) {
return GenericRequest.obtain(
loadProvider,
model,
signature,
context,
priority,
target,
sizeMultiplier,
placeholderDrawable,
placeholderId,
errorPlaceholder,
errorId,
fallbackDrawable,
fallbackResource,
requestListener,
requestCoordinator,
glide.getEngine(),
transformation,
transcodeClass,
isCacheable,
animationFactory,
overrideWidth,
overrideHeight,
diskCacheStrategy);
}
可以看到,buildRequest()
方法的内部其实又调用了buildRequestRecursive()
方法,而buildRequestRecursive()
方法中的代码虽然有点长,但是其中90%的代码都是在处理缩略图的。如果我们只追主线流程的话,那么只需要看第47行代码就可以了。这里调用了obtainRequest()
方法来获取一个Request对象
,而obtainRequest()
方法中又去调用了GenericRequest
的obtain()
方法。注意这个obtain()
方法需要传入非常多的参数,而其中很多的参数我们都是比较熟悉的,像什么placeholderId、errorPlaceholder、diskCacheStrategy
等等。因此,我们就有理由猜测,刚才在load()方法中调用的所有API,其实都是在这里组装到Request对象当中的。那么我们进入到这个GenericRequest的obtain()
方法瞧一瞧:
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,
ResourceCallback {
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(
LoadProvider<A, T, Z, R> loadProvider,
A model,
Key signature,
Context context,
Priority priority,
Target target,
float sizeMultiplier,
Drawable placeholderDrawable,
int placeholderResourceId,
Drawable errorDrawable,
int errorResourceId,
Drawable fallbackDrawable,
int fallbackResourceId,
RequestListener<? super A, R> requestListener,
RequestCoordinator requestCoordinator,
Engine engine,
Transformation transformation,
Class transcodeClass,
boolean isMemoryCacheable,
GlideAnimationFactory animationFactory,
int overrideWidth,
int overrideHeight,
DiskCacheStrategy diskCacheStrategy) {
@SuppressWarnings(“unchecked”)
GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
if (request == null) {
// 33行:
request = new GenericRequest<A, T, Z, R>();
}
request.init(loadProvider,
model,
signature,
context,
priority,
target,
sizeMultiplier,
placeholderDrawable,
placeholderResourceId,
errorDrawable,
errorResourceId,
fallbackDrawable,
fallbackResourceId,
requestListener,
requestCoordinator,
engine,
transformation,
transcodeClass,
isMemoryCacheable,
animationFactory,
overrideWidth,
overrideHeight,
diskCacheStrategy);
return request;
}
}
可以看到,这里在第33行去new了一个GenericRequest
对象,并在最后一行返回,也就是说,obtain()方法实际上获得的就是一个GenericRequest
对象。另外这里又在第35行调用了GenericRequest的init(),里面主要就是一些赋值的代码,将传入的这些参数赋值到GenericRequest的成员变量当中,我们就不再跟进去看了。
好,那现在解决了构建Request对象的问题,接下来我们看一下这个Request对象又是怎么执行的。回到刚才的into()
方法,你会发现在第18行调用了requestTracker.runRequest()
方法来去执行这个Request,那么我们跟进去瞧一瞧,如下所示:
/**
- Starts tracking the given request.
*/
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
这里有一个简单的逻辑判断,就是先判断Glide当前是不是处理暂停状态,如果不是暂停状态就调用Request的begin()
方法来执行Request,否则的话就先将Request添加到待执行队列
里面,等暂停状态解除了之后再执行。
暂停请求的功能仍然不是这篇文章所关心的,这里就直接忽略了,我们重点来看这个begin()
方法。由于当前的Request对象是一个GenericRequest
,因此这里就需要看GenericRequest中的begin()
方法了,如下所示:
@Override
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
这里我们来注意几个细节,首先如果model等于null
,model也就是我们在第二步load()方法中传入的图片URL地址,这个时候会调用onException()
方法。如果你跟到onException()方法里面去看看,你会发现它最终会调用到一个setErrorPlaceholder()
当中,如下所示:
private void setErrorPlaceholder(Exception e) {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = model == null ? getFallbackDrawable() : null;
if (error == null) {
error = getErrorDrawable();
}
if (error == null) {
error = getPlaceholderDrawable();
}
target.onLoadFailed(e, error);
}
这个方法中会先去获取一个error的占位图,如果获取不到的话会再去获取一个loading占位图,然后调用target.onLoadFailed()方法并将占位图传入。那么onLoadFailed()方法中做了什么呢?我们看一下:
public abstract class ImageViewTarget extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {
@Override
public void onLoadStarted(Drawable placeholder) {
view.setImageDrawable(placeholder);
}
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
view.setImageDrawable(errorDrawable);
}
}
很简单,其实就是将这张error占位图显示到ImageView上而已,因为现在出现了异常,没办法展示正常的图片了。而如果你仔细看下刚才begin()方法的第15行,你会发现它又调用了一个target.onLoadStarted()方法,并传入了一个loading占位图,在也就说,在图片请求开始之前,会先使用这张占位图代替最终的图片显示。这也是我们在上一篇文章中学过的placeholder()和error()这两个占位图API底层的实现原理。
好,那么我们继续回到begin()
方法。刚才讲了占位图的实现,那么具体的图片加载又是从哪里开始的呢?是在begin()方法的第10行和第12行。这里要分两种情况,一种是你使用了override() API为图片指定了一个固定的宽高,一种是没有指定。如果指定了的话,就会执行第10行代码,调用onSizeReady()
方法。如果没指定的话,就会执行第12行代码,调用target.getSize()方法。这个target.getSize()方法的内部会根据ImageView的layout_width和layout_height值做一系列的计算,来算出图片应该的宽高。具体的计算细节我就不带着大家分析了,总之在计算完之后,它也会调用onSizeReady()方法。也就是说,不管是哪种情况,最终都会调用到onSizeReady()方法,在这里进行下一步操作。那么我们跟到这个方法里面来:
@Override
public void onSizeReady(int width, int height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
最后我还整理了很多Android中高级的PDF技术文档。以及一些大厂面试真题解析文档。
Android高级架构师之路很漫长,一起共勉吧!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
12行。这里要分两种情况,一种是你使用了override() API为图片指定了一个固定的宽高,一种是没有指定。如果指定了的话,就会执行第10行代码,调用onSizeReady()
方法。如果没指定的话,就会执行第12行代码,调用target.getSize()方法。这个target.getSize()方法的内部会根据ImageView的layout_width和layout_height值做一系列的计算,来算出图片应该的宽高。具体的计算细节我就不带着大家分析了,总之在计算完之后,它也会调用onSizeReady()方法。也就是说,不管是哪种情况,最终都会调用到onSizeReady()方法,在这里进行下一步操作。那么我们跟到这个方法里面来:
@Override
public void onSizeReady(int width, int height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
最后我还整理了很多Android中高级的PDF技术文档。以及一些大厂面试真题解析文档。
[外链图片转存中…(img-daoHxTVg-1714750310553)]
Android高级架构师之路很漫长,一起共勉吧!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!