前言
源码阅读不是一件简单的事情,每次都要花费很长时间来梳理其内部的原理,所以有朋友觉得看一遍看不懂,那很正常,接下来就是考验你耐心的时候。学习源码的目的是:学习它好的地方,吸收起来作为我们项目的开发。作为你想进阶成跟别人有优势的程序员,那么阅读代码是你的基本功,懂得提取别人优秀的代码,进行修改成为你的代码,那就是你牛逼的地方,所以还是静下心来看看源代码吧。当然,阅读代码也不要做到只见树木,不见森林
Glide主要特点
- 支持Memory和Disk图片缓存
- 支持gif和webp格式图片
- 根据Activity/Fragment自动管理其生命周期
- 使用Bitmap Pool可以使Bitmap复用
- 对于回收的Bitmap会主动调用recycle,减小系统回收压力
Glide的分析流程
Glide图片加载只需要简单的一句链式调用即可高效的加载我们的图片,那么其源码的分析流程也是通过以下的三个方法进行分析
Glide.with(context)
.load(url)
.into(imageView);
Glide的with源码分析
一、with源码中实现原理
我们可以通过with的源码看出,with重载方法很多,可以兼容Activity、Fragment、Application等,这里我们主要以Activity来分析,其他的源码分析大同小异,其with方法实现的主要原理如下
二、with源码中涉及到的类
- RequestManagerRetriever:是关联Activity与RequestManager的使者类
- RequestManager:是管理和启动Glide的请求类
- RequestManagerFragment:是一个Fragment
- ActivityFragmentLifecycle:生命周期接口
三、with源码分析
with源码所做的事情
- 将传进来的Activity和RequestManager关联起来
- 将Activity的生命周期和RequestManager的生命周期关联起来
with是如何实现Activity和RequestManager关联起来的?首先进入with源码,按追踪步数阅读
public static RequestManager with(Context context) {
//第一步:拿到RequestManagerRetriever单例
RequestManagerRetriever retriever = RequestManagerRetriever.get();
//第二步:通过RequestManagerRetriever拿到RequestManager,追踪下去
return retriever.get(context);
}
public RequestManager get(Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
//第三步:根据传进来不同的参数,进行对应的方法去获得RequestManager,追踪下去
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RequestManager get(Activity activity) {
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
//这里是做线程的判断和和版本的兼容
return get(activity.getApplicationContext());
} else {
//断言:Activity是否被销毁
assertNotDestroyed(activity);
//获取Activity中的FragmentManager,为后面将隐藏的Fragment依附于Activity上做准备,这里不做分析
android.app.FragmentManager fm = activity.getFragmentManager();
//第四步:根据传进的Activity和FragmentManager,进行对应的方法去获得RequestManager,追踪下去
return fragmentGet(activity, fm);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
//获取隐藏的Fragment
RequestManagerFragment current = getRequestManagerFragment(fm);
//获取当前RequestManager
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
//第五步:如果为空则创建出新的RequestManager,将Activity和生命周期作为参数传递进去
//那么这样子就关联起了Activity与RequestManager
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
//设置当前RequestManager
current.setRequestManager(requestManager);
}
return requestManager;
}
其实上面连贯起来是非常简单的一段代码,那么它们是如何将Activity的生命周期和RequestManager的生命周期关联起来的?我们刚才也分析过,其生命周期的传递过程是由Activity->Fragment->RequestManager,那么这样的一个传递过程是如何实现的呢?
首先当Activity生命周期发生改变时,就会在Fragment中调用相应的方法,我们上面有看到通过getRequestManagerFragment方法,来获取Fragment的,追踪其代码
@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) {
//它是在这里直接创建出新的Fragment,追踪下去
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
public class RequestManagerFragment extends Fragment {
private final ActivityFragmentLifecycle lifecycle;
public RequestManagerFragment() {
//调用自身的构造方法,追踪下去
this(new ActivityFragmentLifecycle());
}
// For testing only.
@SuppressLint("ValidFragment")
RequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
//赋值
this.lifecycle = lifecycle;
}
//根据Activity传进来的不同生命周期方法,调用自身lifecycle的回调方法
//我们上面也知道,这个lifecycle已经传递给了RequestManager
//那么它就会回调RequestManager中对应的lifecycle的回调方法
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
}
目前,生命周期的回调方法已经从Fragment传到RequestManager类中的lifecycle回调,我们上面也分析到创建出新的RequestManager中时,我们进入这个构造方法,看看具体做了什么事情
public class RequestManager implements LifecycleListener {
private final Lifecycle lifecycle;
public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
//第一步:调用自身的构造方法,追踪下去
this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
}
RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
//参数的赋值,将Fragment中的lifecycle传递进来
this.context = context.getApplicationContext();
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.glide = Glide.get(context);
this.optionsApplier = new OptionsApplier();
ConnectivityMonitor connectivityMonitor = factory.build(context,
new RequestManagerConnectivityListener(requestTracker));
if (Util.isOnBackgroundThread()) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//第二步:设置lifecycle的接口回调
lifecycle.addListener(RequestManager.this);
}
});
} else {
//第二步:设置lifecycle的接口回调
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
}
......
//第三步:由于RequestManager已经实现了LifecycleListener,也设置好了lifecycle的接口回调
//那么当有接口方法回调的时候,就会执行对应的方法,也就是Activity发生变化通知Fragment,Fragment通知到这里来
@Override
public void onStart() {
//第四步:根据不同的生命周期,执行不同的Glide请求,这里就不继续分析下去
resumeRequests();
}
@Override
public void onStop() {
pauseRequests();
}
@Override
public void onDestroy() {
requestTracker.clearRequests();
}
}
那么上面涉及到的LifecycleListener,其实就是生命周期的回调接口
public interface LifecycleListener {
void onStart();
void onStop();
void onDestroy();
}
Glide的load源码分析
一、load源码分析
load方法主要是创建DrawableTypeRequest,并将记录相关的uri等数据供后续使用,按追踪步数阅读
public DrawableTypeRequest<String> load(String string) {
//第一步:记录有关对应的参数,最终转成DrawableTypeRequest
return (DrawableTypeRequest<String>) fromString().load(string);
}
public DrawableTypeRequest<String> fromString() {
return loadGeneric(String.class);
}
public DrawableTypeRequest<Uri> load(Uri uri) {
return (DrawableTypeRequest<Uri>) fromUri().load(uri);
}
public DrawableTypeRequest<Uri> fromUri() {
return loadGeneric(Uri.class);
}
public DrawableTypeRequest<File> load(File file) {
return (DrawableTypeRequest<File>) fromFile().load(file);
}
public DrawableTypeRequest<File> fromFile() {
return loadGeneric(File.class);
}
public DrawableTypeRequest<Integer> load(Integer resourceId) {
return (DrawableTypeRequest<Integer>) fromResource().load(resourceId);
}
public DrawableTypeRequest<Integer> fromResource() {
return (DrawableTypeRequest<Integer>) loadGeneric(Integer.class)
.signature(ApplicationVersionSignature.obtain(context));
}
public DrawableTypeRequest<URL> load(URL url) {
return (DrawableTypeRequest<URL>) fromUrl().load(url);
}
public DrawableTypeRequest<URL> fromUrl() {
return loadGeneric(URL.class);
}
load过程分为两步操作
- fromString():创建DrawableTypeRequest
- load():返回当前GenericRequestBuilder
1、追踪fromString()
public DrawableTypeRequest<String> fromString() {
//第二步:调用loadGeneric方法
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);
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");
}
return optionsApplier.apply(
//第三步:创建DrawableTypeRequest,这里追踪下去其实就是一堆参数的赋值,所以没必要再看了
new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
}
2、追踪load()
load采用的是构造者模式,返回GenericRequestBuilder构造者,返回这个类可以构造出图片加载的其他属性,比如:缩略图thumbnail(0.1f)、跳过内存缓存skipMemoryCache(true)、等属性
@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;
//this代表GenericRequestBuilder
return this;
}
Glide的into源码分析
一、into源码分析
into方法主要是使用多线程来加载图片,从into方法开始,按追踪步数阅读
@Override
public Target<GlideDrawable> into(ImageView view) {
//第一步:调用父类into方法,追踪下去
return super.into(view);
}
public Target<TranscodeType> into(ImageView view) {
//判断当前线程,只有主线程才能继续执行
Util.assertMainThread();
if (view == null) {
throw new IllegalArgumentException("You must pass in a non null View");
}
//如果没有设置过transform()或centerCrop,那么以ImageView的scaleType属性为准
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.
}
}
//第二步:这里分为两步
//glide.buildImageViewTarget:创建由Glide自己抽象出来的Target(即泛型的View)
//into:构建请求
return into(glide.buildImageViewTarget(view, transcodeClass));
}
buildImageViewTarget其实就是将我们传进去的View,再封装成Glide抽象的泛型View,它会根据当前传入的clazz参数返回相应的类
<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
//追踪下去
return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}
/**
* 根据当前传入的clazz参数返回相应的Target类
*/
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)");
}
}
我们回到第二步into方法,在这个方法中,主要会构建出一个Request对象,并执行这个Request对象
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对象
Request previous = target.getRequest();
//如果Request存在则回收
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
//第三步:重新构建出一个Request对象
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
//第四步:交给Request追踪器继续执行request
requestTracker.runRequest(request);
return target;
}
我们从第三步开始看起,这里分成三种情况,但最终都会调用obtainRequest,而obtainRequest追踪下去只是对Request的初始化而已
private Request buildRequest(Target<TranscodeType> target) {
if (priority == null) {
priority = Priority.NORMAL;
}
//追踪下去
return buildRequestRecursive(target, null);
}
/*
* 根据不同的逻辑判断构建出不同的Request,前面的分支都是跟缩略图有关的处理
*/
private Request buildRequestRecursive(Target<TranscodeType> 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,追踪下去
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
}
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);
}
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<R> 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<Z> transformation,
Class<R> transcodeClass,
boolean isMemoryCacheable,
GlideAnimationFactory<R> animationFactory,
int overrideWidth,
int overrideHeight,
DiskCacheStrategy diskCacheStrategy) {
@SuppressWarnings("unchecked")
//这里会去对应的Request池找到是否有复用的Request
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的初始化
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;
}
我们从第四步开始看起,runRequest,这里是真正执行的地方。可以看到如果没有处于暂停状态,会直接调用request.begein(),如果处于暂停状态,那么先添加到队列中,等恢复到正常状态时,会再调用request.begin()。即无论如何都会调用request.begin()
public void runRequest(Request request) {
requests.add(request);
//当前是否正在请求
if (!isPaused) {
//第五步:如果没有请求,则开始请求,追踪下去
request.begin();
} else {
//如果有请求,则添加到挂起请求中去
pendingRequests.add(request);
}
}
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//第六步:如果用户设置了Override的方法,那么就会去确定图片的宽高,追踪下去
onSizeReady(overrideWidth, overrideHeight);
} else {
//如果没有设置宽高,则会去测量宽高,最终还是会走到onSizeReady方法中
target.getSize(this);
}
//先加载我们默认的图片
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
@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:负责从数据源中获取原始数据
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
//DataFetcher:负责将图片来源转换成我们需要的图片数据
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
//ResourceTranscoder:负责将我们的IO流解码成Bitmap等
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));
}
}
engine其实就是个Engine类,它是负责启动负载和管理活动和缓存资源。engine.load这个方法中分为两步,第一步处理缓存,第二步真正执行加载, 构建出EngineJob,执行EngineRunnable
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
final String id = fetcher.getId();
//key是用来存储缓存的唯一标识
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
//从内存缓存中获取图片
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
//回调
cb.onResourceReady(cached);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
//从正在使用的图片中获取图片
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
//回调
cb.onResourceReady(active);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
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);
}
EngineRunnable其实就是个Runnable,通过其start方法最终会调用run方法,追踪到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);
}
}
private void onLoadComplete(Resource resource) {
//追踪下去
manager.onResourceReady(resource);
}
@Override
public void onResourceReady(final Resource<?> resource) {
this.resource = resource;
//第十步:通过Handler发送消息,加载图片资源
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
总结
其实Glide的源码解析还有很多东西,大概的流程如下面这张图,后面具体的分析可以看个人兴趣去阅读