写在前面
这篇文章是个人参考源码及博客编写的笔记,主要是对源码简单分析。都是个人对源码的见解记录下来,只是介绍流程,供个人参考,如有需要阅读的,建议对源码和本文进行对照分析或者打开两个界面,以免翻车。文章有点长。
开始:
分析Glide版本:compile 'com.github.bumptech.glide:glide:3.7.0'
查看源码时请对应版本,以免混乱
Glide.with(context).load(url).into(imageView);
上面就是Glide API调用最基本的的流程
点进去Glide 就会看到with方法中会有四个方法,其中的参数又Activity 、context 、fragmentActivity、application
Q1
这里使用的是Activity为参数传递进去
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
在with方法中可以接收五种不同的参数,看下图
444.png
这里只需要对参数为activity情况下进行分析,
RequestManagerRetriever.get() 获取一个RequestManagerRetriever 对象之后,调用get(activity)方法,然后将RequestManagerRetriever
Q2 get(Activity)。
public RequestManager get(Activity activity) {
//判断是否是后台线程,也就是是否在UI线程
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm);
}
}
前面的判断是在判断是否是后台线程,否则为UI线程,如果后台线程,就传入一个application上下文,然后进入到else方法中。先确保它还没销毁(assertNotDestroyed),再调用activity.getFragmentManager()通过activity获取一个Fragment的管理器,然后做为参数传入到fragmentGet(activity, fm) 方法中。
Q3
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
RequestManagerFragment current = getRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
RequestManagerFragment 是继承于fragment,也就是说RequestManagerFragment 其实就是一个
fragment,自定义该类的其实就是在里面创建一个ActivityFragmentLifecycle,并将它的生命周期和
fragment相关联起来;
getRequestManagerFragment(fm)就是创建一个RequestManagerFragment
Q4
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
在创建RequestManagerFragment 的时候,它是通过findFragmentByTag来获取,如果没有就又从
保存的队列里面获取,再没有就new出一个,然后保存入Map中,在添加到FragmentManager中,然后发送一条handle消息,再将RequestManagerFragment返回
我们回到Q3中
在getRequestManagerFragment的时候,如果不是new出来一个新的RequestManager 就不会为空,否则它也会去创建一个RequestManager 并将生命周期的监听和树节点,并将RequestManager 设置到getRequestManagerFragment中去再将RequestManager
这里with的一系列源码已经解析完成了。其主要的目的就是创建一个fragment并且监听绑定它的生命周期变换,以免在glide在图片请求的时候,做一系列的停止等操作。
with方法就是通过监听fragment生命周期对图片进行操作,比如说暂停加载等
接下来就load()
因为with的时候返回的是RequestManager ,所以load就是RequestManager 的方法
在Request有多个load方法
111.png其中包括byte数组、file、uri等等,说明Glide 可以接收多种类型的请求,这里我们对load(String)进行分析
Q5
public DrawableTypeRequest<String> load(String string) {
return (DrawableTypeRequest<String>) fromString().load(string);
}
这个方法会返回一个DrawableTypeRequest类型,并指定它的泛型是String,然后调用
fromString() 再调用load(String)
进去看看fromString
Q6
public DrawableTypeRequest<String> fromString() {
return loadGeneric(String.class);
}
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
ModelLoader<T, InputStream> streamModelLoader= Glide.buildStreamModelLoader(modelClass, context);
ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
Glide.buildFileDescriptorModelLoader(modelClass, context);
....
return optionsApplier.apply(new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,glide, requestTracker, lifecycle, optionsApplier));
}
这个方法很短,调用Glide.buildStreamModelLoader(modelClass, context) 和 Glide.buildFileDescriptorModelLoader(modelClass, context)都返回一个ModelLoader对象。这里我们只要知道 ModelLoader 接口是加载图片的就好,因为里面过于复杂,不做过多介绍。他会根据你传入的参数类型返回相应的对象,我们在fromString方法传入的是String.class,所以这里会返回StreamStringLoader。最后一行会new 一个 DrawableTypeRequest 将 modelClass,StreamStringLoader等参数传进去,并将其返回。
Q7
222.png进入到该类,其他的我们先不要注意,你会发现该类中有asGif(),asBitmap(),这个就是我们在强制指定加载静态图片和动态图片,看看它的方法
Q8
public BitmapTypeRequest<ModelType> asBitmap() {
return optionsApplier.apply(new BitmapTypeRequest<ModelType>(this, streamModelLoader,fileDescriptorModelLoader, optionsApplier));
}
public GifTypeRequest<ModelType> asGif() {
return optionsApplier.apply(new GifTypeRequest<ModelType>(this, streamModelLoader, optionsApplier));
}
源码看出,如果指定了asBitmap()或者asGif(),默认的会使用DrawableTypeRequest,使用fromString()就返回一个DrawableTypeRequest,再来Q5 中的load(Stirng),点进去直接跳到DrawableTypeRequest的父类DrawableRequestBuilder。
Q9
@Override
public DrawableRequestBuilder<ModelType> load(ModelType model) {
super.load(model);
return this;
}
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
this.model = model;
isModelSet = true;
return this;
}
只是简单的赋值并返回this,看看它的全部方法
333.png回发现,我们在调用api的时候,使用的方法大都在这个类中。致此load已经分析好了
看一下into,这个方法较为复杂,这里只分析主线,对于分岔路可以自行去分析。
在load分析的DrawableRequestBuilder类方法的截图中,你会看到一个into(),这个就是into的入口
进去看看:
Q10
public Target<TranscodeType> 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;
//$CASES-OMITTED$
default:
// Do nothing.
}
}
return into(glide.buildImageViewTarget(view, transcodeClass));
}
前面一些代码先不用管,我们先注意一下最后一行代码,into(glide.buildImageViewTarget(view, transcodeClass)); 在into当中调用glide.buildImageViewTarget(view, transcodeClass),老规矩,进去看看
Q11
<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}
紧接的是调用一个buildTarget
Q12
public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
if (GlideDrawable.class.isAssignableFrom(clazz)) {
return (Target<Z>) new GlideDrawableImageViewTarget(view);
} else if (Bitmap.class.equals(clazz)) {
return (Target<Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (Target<Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException("Unhandled class: " + clazz
+ ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
这里会根据class来判断要创建哪个对象,这里我们只需要知道会返回一个 GlideDrawableImageViewTarget对象,因为如果要分析其class的话,还要需要很大的功夫,这里我们只关心主线,返回GlideDrawableImageViewTarget,我们回到Q10中的最后一行代码,into(GlideDrawableImageViewTarget),
Q13
public <Y extends Target<TranscodeType>> 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);
requestTracker.runRequest(request);
return target;
}
其中target.getRequest()是获取当前的taget是否有请求,如果存在就将它清空回收,然后在重新创建一个Request请求对象,也就是调用huildRequest(target),
我们看看 buildRequest(target)方法,会返回一个Request类型,
Q14
private Request buildRequest(Target<TranscodeType> target) {
if (priority == null) {
priority = Priority.NORMAL;
}
return buildRequestRecursive(target, null);
}
再调用buildRequestRecursive 把 GlideDrawableImageViewTarget 和 null 丢进去
Q15
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
.....
} else {
// Base case: no thumbnail.
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
}
主要看最后一行 obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
Q16
private Request obtainRequest(Target<TranscodeType> 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);
}
紧接的会将一些乱七八糟的参数传入到 GenericRequest.obtain(..)方法中
Q17
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(....) {
@SuppressWarnings("unchecked")
GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
if (request == null) {
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;
}
这里会调用request = new GenericRequest<A, T, Z, R>() 创建出一个GenericRequest对象,并将这些乱七八糟的参数传进来,并返回GenericRequest,其中很多的参数我们都是比较熟悉的,像什么placeholderId、errorPlaceholder、diskCacheStrategy等等,这里可以看出,刚才在GenericRequestBuilder中设置的参数都会封装到此处来,也就是Glide的API,所以在Q13中的buildRequest(target); 返回来的Request对象,其实就是GenericRequest,GenericRequest里面封装这api中的属性值。
接下来我们回到Q13中,看看这个方法 requestTracker.runRequest(request) ,调用runRequest将GenericRequest传递过去,来看看runRequest方法
Q18
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
这里判断Glide状态是否为停止的状态,然后调用GenericRequest的begin() 方法,否则将Request添加到待执行队列,所以我们进去看看GenericRequest的begin方法
Q19
@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));
}
}
我们先看看onException(null) ,先判断model是否为空,mode就是在Q9 中 load传过来的String,也就是uri,也就是说uri为空的时候,就会调用onException方法,进去看看
Q20
@Override
public void onException(Exception e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "load failed", e);
}
status = Status.FAILED;
//TODO: what if this is a thumbnail request?
if (requestListener == null || !requestListener.onException(e, model, target, isFirstReadyResource())) {
setErrorPlaceholder(e);
}
}
经过一系列的判断后,会调用setErrorPlaceholder(e),看名字就知道,他就是用来设置占位符的,也就是错误图片
Q21
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是否为空之后,就会获取一个error图片,还是没有的话再获取一个placeholder图片
然后调用target.onLoadFailed(e, error) 这个tagat就是Q11 和Q12中的GlideDrawableImageViewTarget ,进去之后onLoadFailed()是在它父类ImageViewTarget中
Q22
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
view.setImageDrawable(errorDrawable);
}
只是将Drawable 设置进ImageView中去。onExption()方法就是这样,所以我们接下来回到Q19 对下面就行分析,
Q23
@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));
}
}
这里会调用到onSizeReady() 方法,这个宽高是自定义的宽高,是通过一系列的运算之后得到的宽高,点击进去看看这个方法,
Q24
@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;
}
status = Status.RUNNING;
width = Math.round(sizeMultiplier * width);
height = Math.round(sizeMultiplier * height);
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
这时会看到一个loadProvider.getModeLoader()方法,在同getModeLoader之后获取到一个ModeLoader对象在调用它的getResource(model,width,height);方法获取到一个DataFetcher对象,这里先去了解一下loadProvider.getModeLoader()的方法,这个loadProvider其实就是分析load()方法的时候进行初始化的,我们回到在Q6 中在loadGeneric的时候,会创建出一个DrawableTypeRequest,在构造方法的时候,会调用super方法,super方法的第三个参数当中需要传入一个LoadProvider 对象,然后就会调用buildProvider加载出一个LoadProvider对象,想看看这个类
Q25
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> 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<Z> resourceClass,Class<R> 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<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,fileDescriptorModelLoader);
return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
}
DrawableTypeRequest(Class<ModelType> 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;
}
public BitmapTypeRequest<ModelType> asBitmap() {
return optionsApplier.apply(new BitmapTypeRequest<ModelType>(this, streamModelLoader,
fileDescriptorModelLoader, optionsApplier));
}
public GifTypeRequest<ModelType> asGif() {
return optionsApplier.apply(new GifTypeRequest<ModelType>(this, streamModelLoader, optionsApplier));
}
}
先看看 transcoder = glide.buildTranscoder(resourceClass, transcodedClass),这里你只要知道会返回一个ResourceTranscoder的子类GifBitmapWrapperDrawableTranscoder对象,它是用于对图片进行转码,紧接的就是glide.buildDataProvider(ImageVideoWrapper.class, resourceClass) 构建一个DataLoadProvider,这里你也需要只知道它是创建一个ImageVideoGifDrawableLoadProvider
对象,再接的就是new ImageVideoModelLoader 将在Q6 中构建的ModelLoade封装进去,最后就是通过 new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider); 将ImageVideoModelLoader,GifBitmapWrapperDrawableTranscoder,ImageVideoGifDrawableLoadProvider封装进去,所以在Q24中的loadProvider其实就是FixedLoadProvider,也就是说loadProvider.getModelLoader()获取的就是封装进去的ImageVideoModelLoader,接下来回到Q24中,会通过ImagVideoModelLoader对象调用这个modelLoader.getResourceFetcher(model, width, height)方法获取到一个DataFetcher对象,进去看看ImagVideoModelLoader这个类
Q26
public class ImageVideoModelLoader<A> implements ModelLoader<A, ImageVideoWrapper> {
private static final String TAG = "IVML";
private final ModelLoader<A, InputStream> streamLoader;
private final ModelLoader<A, ParcelFileDescriptor> fileDescriptorLoader;
public ImageVideoModelLoader(ModelLoader<A, InputStream> streamLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorLoader) {
if (streamLoader == null && fileDescriptorLoader == null) {
throw new NullPointerException("At least one of streamLoader and fileDescriptorLoader must be non null");
}
this.streamLoader = streamLoader;
this.fileDescriptorLoader = fileDescriptorLoader;
}
@Override
public DataFetcher<ImageVideoWrapper> getResourceFetcher(A model, int width, int height) {
DataFetcher<InputStream> streamFetcher = null;
if (streamLoader != null) {
streamFetcher = streamLoader.getResourceFetcher(model, width, height);
}
DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher = null;
if (fileDescriptorLoader != null) {
fileDescriptorFetcher = fileDescriptorLoader.getResourceFetcher(model, width, height);
}
if (streamFetcher != null || fileDescriptorFetcher != null) {
return new ImageVideoFetcher(streamFetcher, fileDescriptorFetcher);
} else {
return null;
}
}
static class ImageVideoFetcher implements DataFetcher<ImageVideoWrapper> {
private final DataFetcher<InputStream> streamFetcher;
private final DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher;
public ImageVideoFetcher(DataFetcher<InputStream> streamFetcher,
DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher) {
this.streamFetcher = streamFetcher;
this.fileDescriptorFetcher = fileDescriptorFetcher;
}
}
@SuppressWarnings("resource")
// @see ModelLoader.loadData
@Override
public ImageVideoWrapper loadData(Priority priority) throws Exception {
InputStream is = null;
if (streamFetcher != null) {
try {
is = streamFetcher.loadData(priority);
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception fetching input stream, trying ParcelFileDescriptor", e);
}
if (fileDescriptorFetcher == null) {
throw e;
}
}
}
ParcelFileDescriptor fileDescriptor = null;
if (fileDescriptorFetcher != null) {
try {
fileDescriptor = fileDescriptorFetcher.loadData(priority);
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception fetching ParcelFileDescriptor", e);
}
if (is == null) {
throw e;
}
}
}
return new ImageVideoWrapper(is, fileDescriptor);
}
}
看看getResourceFetcher方法中,获取一个streamFetcher ,streamLoader就是我们在loadGeneric()方法中创建的StreamStringLoader,调用他的getResourceFetcher就是得到一个HttpUrlFetcher,后面就是new ImageVideoFetcher 将HttpUrlFetcher和StreamStringLoader传进去,所以,我们在Q24得到的DataFetcher其实就是这个ImageVideoFetcher ,回到Q24中,接下来就是调用 engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,priority, isMemoryCacheable, diskCacheStrategy, this) 其中dataFetcher
就是我们的ImageVideoFetcher,loadProvider就是 Q24中的FixedLoadProvider,transcoder就是FixedLoadProvider中的GifBitmapWrapperDrawableTranscoder,其中还包括是否开启内存缓存,硬盘缓存策略,还有一个this,这个this就是ResourceCallback接口,这个接口GenericRequest已经实现,然后就是engine中的load方法,
Q26.1
public <T, Z, R> LoadStatus load(....) {
.....
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
看到一个engineJobFactory.build(...)其实就是创建一个EngineJob 对象,它是用来开启线程的,为后面的异步加载图片做准备。然后就是DecodeJob对象,是用来给是图片进行解码的。
还有一个EngineRunnable,看名字就知道的,它是一个Runnable的子类,任何将DecodeJob,EngineJob 传进去,所以看看它的run方法,
Q27
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
resource = decode();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
exception = e;
}
if (isCancelled) {
if (resource != null) {
resource.recycle();
}
return;
}
if (resource == null) {
onLoadFailed(exception);
} else {
onLoadComplete(resource);
}
}
这个run方法一旦运行,就说明它是在子线程中运行了,其中里面包括一个decode()方法
Q28
private Resource<?> decode() throws Exception {
if (isDecodingFromCache()) {
return decodeFromCache();
} else {
return decodeFromSource();
}
}
这里会判断它是否是从缓存中去解码图片就会调用decodeFromCache,否则就调用decodeFromSource,我们先看看decodeFromSource方法,
Q29
private Resource<?> decodeFromSource() throws Exception {
return decodeJob.decodeFromSource();
}
接着他会调用DecodeJob对象中的decodeFromSource方法,
Q30
public Resource<Z> decodeFromSource() throws Exception {
Resource<T> decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}
接着就是再调用decodeSource() 获取一个Resource对象,再调用transformEncodeAndTranscode()将Resource对象传进去处理,再返回一个Resource对象。先进入到decodeSource中,
Q31
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
long startTime = LogTime.getLogTime();
final A data = fetcher.loadData(priority);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Fetched data", startTime);
}
if (isCancelled) {
return null;
}
decoded = decodeFromSourceData(data);
} finally {
fetcher.cleanup();
}
return decoded;
}
注意到一个方法,fetcher.loadData(priority),返回一个A,这个fercher就是在Q24、25、26中通过
ImagVideoModelLoader得到一个ImageVideoFetcher对象,再来调用他的loadData方法,所以进去瞧一瞧
Q32
@Override
public ImageVideoWrapper loadData(Priority priority) throws Exception {
InputStream is = null;
if (streamFetcher != null) {
try {
is = streamFetcher.loadData(priority);
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception fetching input stream, trying ParcelFileDescriptor", e);
}
if (fileDescriptorFetcher == null) {
throw e;
}
}
}
ParcelFileDescriptor fileDescriptor = null;
if (fileDescriptorFetcher != null) {
try {
fileDescriptor = fileDescriptorFetcher.loadData(priority);
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception fetching ParcelFileDescriptor", e);
}
if (is == null) {
throw e;
}
}
}
return new ImageVideoWrapper(is, fileDescriptor);
}
就在这里,InputStream is = streamFetcher.loadData(priority); 这货返回一个InputStream 对象,也就是说streamFetcher.loadData(priority)就是请求数据返回来的图片流,这个streamFetcher就是在Q26 中new ImageVideoFetcher时传的HttpUrlFetcher和StreamStringLoader中的HttpUrlFetcher,所以这个streamFetcher.loadData(priority)就是调用HttpUrlFetcher中的loadData方法,看看呗
Q33
@Override
public InputStream loadData(Priority priority) throws Exception {
return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers)throws IOException {
if (redirects >= MAXIMUM_REDIRECTS) {
throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
// Comparing the URLs using .equals performs additional network I/O and is generally broken.
// See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new IOException("In re-direct loop");
}
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
}
}
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(2500);
urlConnection.setReadTimeout(2500);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
// Connect explicitly to avoid errors in decoders if connection fails.
urlConnection.connect();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (statusCode / 100 == 2) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (statusCode / 100 == 3) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new IOException("Received empty or null redirect url");
}
URL redirectUrl = new URL(url, redirectUrlString);
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else {
if (statusCode == -1) {
throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
}
throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
}
}
这些就是网络请求,返回一个InputStream 对象,回到Q32中,最后一行的new ImageVideoWrapper(is, fileDescriptor),返回一个ImageVideoWrapper对象,然后将InputStream 封装进去,所以在Q31中的A 类型就是ImageVideoWrapper对象,Q31 DecodeJob.decodeSource中的final A data = fetcher.loadData(priority)分析完了,在回头看看Q31中,看这一行,decoded = decodeFromSourceData(data),将ImageVideoWrapper对象传进去
Q34
private Resource<T> decodeFromSourceData(A data) throws IOException {
final Resource<T> decoded;
if (diskCacheStrategy.cacheSource()) {
decoded = cacheAndDecodeSourceData(data);
} else {
long startTime = LogTime.getLogTime();
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded from source", startTime);
}
}
return decoded;
}
注意这个 decoded = loadProvider.getSourceDecoder().decode(data, width, height);这个方法,loadProvider就是FixedLoadProvider,在Q25中有解释,调用他的getSourceDecoder()获取到他在构造的时候传进去的ImageVideoGifDrawableLoadProvider对象,在调用它在构造方法中创建的GifBitmapWrapperResourceDecoder对象,再调用GifBitmapWrapperResourceDecoder的decode方法,
Q35
@SuppressWarnings("resource")
// @see ResourceDecoder.decode
@Override
public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException {
ByteArrayPool pool = ByteArrayPool.get();
byte[] tempBytes = pool.getBytes();
GifBitmapWrapper wrapper = null;
try {
wrapper = decode(source, width, height, tempBytes);
} finally {
pool.releaseBytes(tempBytes);
}
return wrapper != null ? new GifBitmapWrapperResource(wrapper) : null;
}
再调用它的decode重载方法
Q36
private GifBitmapWrapper decode(ImageVideoWrapper source, int width, int height, byte[] bytes) throws IOException {
final GifBitmapWrapper result;
if (source.getStream() != null) {
result = decodeStream(source, width, height, bytes);
} else {
result = decodeBitmapWrapper(source, width, height);
}
return result;
}
判断source是否为空,sourcek就是ImageVideoWrapper,也就是刚才的A类型,传入到decodeFromSourceData(data)方法,而这个ImageVideoWrapper是持有InputStream对象的,是有这里不等于空,则调用decodeStream,
Q37
private GifBitmapWrapper decodeStream(ImageVideoWrapper source, int width, int height, byte[] bytes)throws IOException {
InputStream bis = streamFactory.build(source.getStream(), bytes);
bis.mark(MARK_LIMIT_BYTES);
ImageHeaderParser.ImageType type = parser.parse(bis);
bis.reset();
GifBitmapWrapper result = null;
if (type == ImageHeaderParser.ImageType.GIF) {
result = decodeGifWrapper(bis, width, height);
}
// Decoding the gif may fail even if the type matches.
if (result == null) {
// We can only reset the buffered InputStream, so to start from the beginning of the stream, we need to
// pass in a new source containing the buffered stream rather than the original stream.
ImageVideoWrapper forBitmapDecoder = new ImageVideoWrapper(bis, source.getFileDescriptor());
result = decodeBitmapWrapper(forBitmapDecoder, width, height);
}
return result;
}
这里先判断是否为GIF,是就调用decodeGifWrapper(bis, width, height),否则会创建一个ImageVideoWrapper 对象,调用decodeBitmapWrapper(forBitmapDecoder, width, height)传进去,所以加载普通图片就先进入到decodeBitmapWrapper方法中
Q38
private GifBitmapWrapper decodeBitmapWrapper(ImageVideoWrapper toDecode, int width, int height) throws IOException {
GifBitmapWrapper result = null;
Resource<Bitmap> bitmapResource = bitmapDecoder.decode(toDecode, width, height);
if (bitmapResource != null) {
result = new GifBitmapWrapper(bitmapResource, null);
}
return result;
}
通过调用 bitmapDecoder.decode(toDecode, width, height) 返回一个Resource对象,再将它封装到GifBitmapWrapper中,这个ditmapDecoder我们只要知道是一个 ImageVideoBitmapDecoder对象,我们只要往主线走,我们看一下他的方法,
Q39
@Override
public Resource<Bitmap> decode(ImageVideoWrapper source, int width, int height) throws IOException {
Resource<Bitmap> result = null;
InputStream is = source.getStream();
if (is != null) {
try {
result = streamDecoder.decode(is, width, height);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Failed to load image from stream, trying FileDescriptor", e);
}
}
}
if (result == null) {
ParcelFileDescriptor fileDescriptor = source.getFileDescriptor();
if (fileDescriptor != null) {
result = fileDescriptorDecoder.decode(fileDescriptor, width, height);
}
}
return result;
}
在获取到ImageVideoWrapper 中的InputStream,之后再调用streamDecoder.decode(is, width, height);获取一个Resource<Bitmap> 泛型为Bitmap,这个streamDecoder只需要知道他是StreamBitmapDecoder对象,再来看看他的decode方法,
Q40
@Override
public Resource<Bitmap> decode(InputStream source, int width, int height) {
Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat);
return BitmapResource.obtain(bitmap, bitmapPool);
}
然后。。它又去调用 downsampler.decode(source, bitmapPool, width, height, decodeFormat) 返回一个Bitmap对象,再封装到Resource中,downsampler就是Downsampler,里面主要是将InputStream 处理得到一个Bitmap对象,再是用BitmapResource将其封装,
Q41
public static BitmapResource obtain(Bitmap bitmap, BitmapPool bitmapPool) {
if(bitmap == null) {
return null;
}else{
return new BitmapResource(bitmap, bitmapPool);
}
}
是的,就是new 一个BitmapResource,所以得出,在Q38中streamDecoder.decode(is, width, height)方法中获取的就是一个BitmapResourced对象,然后在将BitmapResource对象封装到GifBitmapWrapper方法中,然后返回一步一步向上返回GifBitmapWrapper,Q38 到 Q37 到Q36 到Q35 ,那回到 Q35
@Override
public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException {
ByteArrayPool pool = ByteArrayPool.get();
byte[] tempBytes = pool.getBytes();
GifBitmapWrapper wrapper = null;
try {
wrapper = decode(source, width, height, tempBytes);
} finally {
pool.releaseBytes(tempBytes);
}
return wrapper != null ? new GifBitmapWrapperResource(wrapper) : null;
}
最后一行又创建了一次GifBitmapWrapperResource对GifBitmapWrapper进行封装,然后将GifBitmapWrapperResource返回到Q34 ,GifBitmapWrapperResource是继承自Resource,所以将这个GifBitmapWrapperResource返回到Q34,再到Q31,然后在到Q30
到Q30 看看,我们刚刚就是分析的decodeSource,返回一个GifBitmapWrapperResource(wrapper) ,将GifBitmapWrapperResource 传入到transformEncodeAndTranscode方法中
public Resource<Z> decodeFromSource() throws Exception {
Resource<T> decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}
transformEncodeAndTranscode方法的返回值也是一个Resource对象,不过他的泛型是不一样的,一个Z 一个T,先看看这个方法吧
Q42
private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
long startTime = LogTime.getLogTime();
Resource<T> transformed = transform(decoded);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transformed resource from source", startTime);
}
writeTransformedToCache(transformed);
startTime = LogTime.getLogTime();
Resource<Z> result = transcode(transformed);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transcoded transformed from source", startTime);
}
return result;
}
注意到 Resource<Z> result = transcode(transformed) 这段代码,又调用trancode(transformed)来看看
Q43
private Resource<Z> transcode(Resource<T> transformed) {
if (transformed == null) {
return null;
}
return transcoder.transcode(transformed);
}
transcoder是在DecodeJob初始化的时候传来,初始化的时候是在Engine.load(Q26) 的方法中,而调用Engine.load是在GenericRequest的onSizeReady(Q24)中,通过loadProvider.getTranscoder()获取出来的
而这个loadProvider就是Q25中创建出来的 FixedLoadProvider并传入3个参数,而他获取getTranscoder()就是Q25中初始化传入的GifBitmapWrapperDrawableTranscoder,我们看一下GifBitmapWrapperDrawableTranscoder中的transcode方法
Q44
public Resource<GlideDrawable> transcode(Resource<GifBitmapWrapper> toTranscode) {
GifBitmapWrapper gifBitmap = toTranscode.get();
Resource<Bitmap> bitmapResource = gifBitmap.getBitmapResource();
final Resource<? extends GlideDrawable> result;
if (bitmapResource != null) {
result = bitmapDrawableResourceTranscoder.transcode(bitmapResource);
} else {
result = gifBitmap.getGifResource();
}
// This is unchecked but always safe, anything that extends a Drawable can be safely cast to a Drawable.
return (Resource<GlideDrawable>) result;
}
可以看到,它是先从GifBitmapWrapperResource中取出GifBitmapWrapper,再从GifBitmapWrapper中取出BitmapResource (Q38,39,40,41 有解释了),然后判断是否为空之后调用bitmapDrawableResourceTranscoder.transcode(bitmapResource),否则调用gifBitmap.getGifResource()方法加载一个gif图片。跟GifBitmapWrapperDrawableTranscoder一样,只需要知道这个bitmapDrawableResourceTranscoder是GlideBitmapDrawableTranscoder对象就可以了,否则分析会不完。所以接下来就会调用GlideBitmapDrawableTranscoder中的transcode方法将BitmapResource 传进去。
Q45
@Override
public Resource<GlideBitmapDrawable> transcode(Resource<Bitmap> toTranscode) {
GlideBitmapDrawable drawable = new GlideBitmapDrawable(resources, toTranscode.get());
return new GlideBitmapDrawableResource(drawable, bitmapPool);
}
这里面又做了两个动作,new GlideBitmapDrawable对象,并获取出BitmapResource 中的Bitmap封装到里面,在返回一个GlideBitmapDrawableResource,又把GlideBitmapDrawable传进去返回,所以Q44当中返回的就是GlideBitmapDrawableResource对象,返回的就是Resource<GlideBitmapDrawable>,Q42 中的这个Z就是GlideBitmapDrawable,所以我们回到Q44当中,这个Resource<? extends GlideDrawable> result 就是GlideBitmapDrawableResource<GlideBitmapDrawable> 将它返回到Q42 再返回到 Q30中再到Q27 (跨度又点大),也就是回到EngineRunnable的run方法中。
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
resource = decode();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
exception = e;
}
if (isCancelled) {
if (resource != null) {
resource.recycle();
}
return;
}
if (resource == null) {
onLoadFailed(exception);
} else {
onLoadComplete(resource);
}
}
这个 decode() 有够深的,decode返回的就是上面分析的Resource<GlideDrawable>,最后判断是否为空之后,调用onLoadComplete传进去,
Q46
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
}
这个manager就是Q26 传的EngineJob对象,看看呗
Q47
@Override
public void onResourceReady(final Resource<?> resource) {
this.resource = resource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
将 Resource<?> resource赋值给成员变量之后,发送一个消息,把自己传过去。Handler 就是EngineJob中的静态内部类,在run方法运行后就一直在子线程中执行上面分析的逻辑代码,只有在这里的时候才通过handler回到子线程当中来,所以可以猜到,接下来的代码就是执行图片展示的代码。
Q48
private static class MainThreadCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message message) {
if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {
EngineJob job = (EngineJob) message.obj;
if (MSG_COMPLETE == message.what) {
job.handleResultOnMainThread();
} else {
job.handleExceptionOnMainThread();
}
return true;
}
return false;
}
}
接下来就是调用 EngineJob 中的 handleResultOnMainThread方法,
Q49
private void handleResultOnMainThread() {
......
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource);
}
}
// Our request is complete, so we can release the resource.
engineResource.release();
}
看到一个for循环,遍历获取cbs,cbs是一个成员变量的集合private final List<ResourceCallback> cbs = new ArrayList<ResourceCallback>(),通过遍历获取到ResourceCallback ,那么ResourceCallback 添加是在什么时候的?在EngineJob的时候还有一个add的方法,
Q50
public void addCallback(ResourceCallback cb) {
Util.assertMainThread();
if (hasResource) {
cb.onResourceReady(engineResource);
} else if (hasException) {
cb.onException(exception);
} else {
cbs.add(cb);
}
}
最后就是cbs.add 将传进来的参数添加进集合中。这个addCallback方法就在Engine.load(Q26 )中调用的,而且是作为load的参数传进来的,我们在Q24Q25的时候有分析过,在GenericRequst.onSizeReady()方法中我们调用engine.load时传入很多参数,在最后一个参数的时候会传入一个this,也就是GenericRequst的本身,也就是GenericRequst实现了ResourceCallback接口,所以EngineJob最终调用的就是GenericRequst的onResourceReady方法。
Q51
public void onResourceReady(Resource<?> resource) {
if (resource == null) {
onException(new Exception("Expected to receive a Resource<R> with an object of " + transcodeClass
+ " inside, but instead got null."));
return;
}
Object received = resource.get();
if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
releaseResource(resource);
onException(new Exception("Expected to receive an object of " + transcodeClass
+ " but instead got " + (received != null ? received.getClass() : "") + "{" + received + "}"
+ " inside Resource{" + resource + "}."
+ (received != null ? "" : " "
+ "To indicate failure return a null Resource object, "
+ "rather than a Resource object containing null data.")
));
return;
}
if (!canSetResource()) {
releaseResource(resource);
// We can't set the status to complete before asking canSetResource().
status = Status.COMPLETE;
return;
}
onResourceReady(resource, (R) received);
}
先获取到resource.get() ,也就是上面分析的Q45 中的GlideBitmapDrawable, 再作为参数调用他的重载方法,
Q52
private void onResourceReady(Resource<?> resource, R result) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,isFirstResource)) {
GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
target.onResourceReady(result, animation);
}
notifyLoadSuccess();
}
这里只要看到他的 target.onResourceReady(result, animation)方法,target知道,也就是前面分析(Q12)中的封装ImageView的GlideDrawableImageViewTarget对象,调用它的onResourceReady方法
Q53
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {
if (!resource.isAnimated()) {
//TODO: Try to generalize this to other sizes/shapes.
// This is a dirty hack that tries to make loading square thumbnails and then square full images less costly
// by forcing both the smaller thumb and the larger version to have exactly the same intrinsic dimensions.
// If a drawable is replaced in an ImageView by another drawable with different intrinsic dimensions,
// the ImageView requests a layout. Scrolling rapidly while replacing thumbs with larger images triggers
// lots of these calls and causes significant amounts of jank.
float viewRatio = view.getWidth() / (float) view.getHeight();
float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight();
if (Math.abs(viewRatio - 1f) <= SQUARE_RATIO_MARGIN
&& Math.abs(drawableRatio - 1f) <= SQUARE_RATIO_MARGIN) {
resource = new SquaringDrawable(resource, view.getWidth());
}
}
super.onResourceReady(resource, animation);
this.resource = resource;
resource.setLoopCount(maxLoopCount);
resource.start();
}
然后会调用父类的 super.onResourceReady(resource, animation);方法,
Q54
@Override
public void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) {
if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
setResource(resource);
}
}
protected abstract void setResource(Z resource);
父类只是调用了它的 setResource 方法,而setResource 方法是一个抽象方法,所以它会调用自己的setResource 方法,
Q55
@Override
protected void setResource(GlideDrawable resource) {
view.setImageDrawable(resource);
}
这个view就是封装的ImageView,然后将GlideDrawable 设置进来,至此,一个图片就展示出来了。
总结:
本文只是简单的分析,供个人参考
网友评论