文章目录
.into(*)
这个方法非常的复杂,得反复看好几遍源码。 —— 鲁迅
以 .into(ImageView) 为例,我们看看这个方法究竟做了哪些事情:
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
BaseRequestOptions<?> requestOptions = this;
//省略验证及一些设置性的代码
...
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
1、Target
看到上面的源码,最终又会调用另一个重载的方法:private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor)
我们只看第一个参数,是一个泛型,这个参数是由glideContext.buildImageViewTarget(view, transcodeClass)来赋值的:
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
//我们对transcodeClass进行追根溯源,这个类型在之前调用 .load()的时候
//已经默认赋值为Drawable.class
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
//因为已经知道是Drawable.class 所以走这条分支
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
可以看的出glideContext.buildImageViewTarget(view, transcodeClass)创建了一个Target,深入探查这个DrawableImageViewTarget,我们发现这个类具有生命周期,包含view实例,包含请求,包含请求结果类型。
2、Request
继续追踪重载的into() 方法:
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
......
//创建一个Request实例
Request request = buildRequest(target, targetListener, options, callbackExecutor);
......
requestManager.clear(target);
//之前说过 Target包含一个请求,那么这个请求就是在这里被初始化的。
target.setRequest(request);
requestManager.track(target, request);
return target;
}
我们直接跟踪buildRequest(target, targetListener, options, callbackExecutor),由于牵扯过深,我以伪代码的形式展示:
if(设置了错误请求){
var requestMain = if(设置了缩略图){
初始化一个请求(包含缩略图)
}else{
初始化一个请求
}
var requestError = 初始化一个请求(包含错误请求)
return requestMain + requestError //可看作功能性的结合
}else{
var requestMain = if(设置了缩略图){
初始化一个请求(包含缩略图)
}else{
初始化一个请求
}
return requestMain
}
这些请求有三种:1、主请求(用于正常的请求网络图片);2、缩略图请求;3、错误请求。
通过上面这个方法,会生成一个组合过的请求(原谅我这么直白的解释),为什么叫组合过呢?因为这些功能都是单独存在的,我们的一个请求可以包含这三种功能,并且这三种功能的执行都是有顺序的,通过:
public void setRequests(Request primary, Request error) {
this.primary = primary;
this.error = error;
}
这个方法,来指定哪个请求在前,哪个请求在后。
最重要的一点:方法返回的是Request对象,这是个接口,这些request对象的实现都是SingleRequest类型。
走到这里我们赶紧做个小结:通过上面的一行代码就已经生成了请求对象了,这个请求对象可能还包含了错误请求和缩略图请求,反正是一个完整的请求对象。接下来就是看它如何执行这个请求。
3、track()
还是在 into() 的那个重载方法里,搞完Request我们继续往下看,就三行代码:
requestManager.clear(target); //1
target.setRequest(request); //2
requestManager.track(target, request); //3
public synchronized void clear(@Nullable final Target<?> target) {
if (target == null) {
return;
}
untrackOrDelegate(target);
}
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
- 如果按照我们目前的走法来看,target的request一定是为null的,所以这行代码没什么作用。
- 就是将request加到target上。
- 方法的名字为:跟踪,进入方法里面看,只有两行代码,分别是targetTracker对象来跟踪target,requestTracker对象来跟踪request,显而易见,这里肯定有大文章!
3.1 生命周期
targetTracker.track(target);这行代码就很简单了:
public void track(@NonNull Target<?> target) {
targets.add(target);
}
直接就是把这个target添加到一个Set集合里面,再看看这个TargetTracker中的代码:
@Override
public void onStart() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onStart();
}
}
@Override
public void onStop() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onStop();
}
}
@Override
public void onDestroy() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onDestroy();
}
}
一看就知道,是用于统一管理target对象的生命周期的,我们看看TargetTracker有在哪里用到过?只有一个地方,那就是RequestManager中:private final TargetTracker targetTracker = new TargetTracker();
直接作为RequestManager的属性,并且RequestManager也含有生命周期的方法(因为它实现了LifecycleListener接口):
//此处只列举一处
@Override
public synchronized void onStart() {
resumeRequests();
targetTracker.onStart();
}
而RequestManager又是作为SupportRequestManagerFragment的属性,为了禁止套娃,我们先屡屡:
- 在初始化Glide的时候,如果 .with(*) 传入的是非applicationContext的话,就会创建一个Fragment,该Fragment与Activity直接关联,那么该Fragment就会感应到Activity的生命周期。
- 按照我们的思路,当Fragment的生命周期发生变化,那么就可以直接调用Fragment中RequestManager对应的生命周期方法(例如:requestManager.onStart())。
- 在RequestManager对应的生命周期方法中,又可以调用其TargetTracker的生命周期方法。
如此一来
当然,以上3点中,第2点和第3点都是我个人的猜想……
事实上,如果这么做的话,也是十分可行的,可人家Glide就是要想的更周到一点!
以上第2、3点的猜想基本上正确,但是人家Glide又添加了一层: ActivityFragmentLifecycle(你以为我是第二层,其实我已经第五层了)
在SupportRequestManagerFragment中,它并没有直接在生命周期方法中调用RequestManager的生命周期方法(所以上面第二点有点小问题),而是调用ActivityFragmentLifecycle的生命周期方法:
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
那么看一下这个ActivityFragmentLifecycle在哪里初始化的:
public SupportRequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
@VisibleForTesting
@SuppressLint("ValidFragment")
public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
原来是直接new出来的,这就好办了,那么我们直接看看这个对象的生命周期方法长啥样:
void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
@Override
public void addListener(@NonNull LifecycleListener listener) {
lifecycleListeners.add(listener);
...
}
看到这里你是不是明白为什么要多加一层ActivityFragmentLifecycle了嘛?就是方便同时管理多个生命周期的监听。
在RequestManager中我们也找到了关键代码:
如果在主线程中,直接执行:lifecycle.addListener(this);
如果在非主线程中,会使得handler post一个任务到主线程中执行:lifecycle.addListener(RequestManager.this);
生命周期的管理到此就结束了。
3.2 requestTracker.runRequest(Request)
我们赶紧跟着主线任务走~
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
在生命周期为onStart()的时候,会调用isPaused = false;,所以直接走request.begin(),记得之前讲过这个request是SingleRequest:
@Override
public synchronized void begin() {
//省略验证及其他代码
...
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) { //1
onSizeReady(overrideWidth, overrideHeight); //3
} else {
target.getSize(this); //2
}
//省略Placeholder相关代码
...
}
- 这行代码是验证是否设置了图片的宽高,默认的宽高=UNSET=-1,如果我们没有设置宽高,就会走2
- 这里的target是Target接口,具体实现是哪个还记得吗?就是那个DrawableImageViewTarget,我们层层找到这个方法:
public void getSize(@NonNull SizeReadyCallback cb) {
sizeDeterminer.getSize(cb);
}
void getSize(@NonNull SizeReadyCallback cb) {
int currentWidth = getTargetWidth();
int currentHeight = getTargetHeight();
if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
cb.onSizeReady(currentWidth, currentHeight);
return;
}
...
}
这里会拿到ImageView的宽高,并且验证是否大于0,如果大于0就回调SizeReadyCallback接口的 onSizeReady() 方法。
- 如果我们手动设置了宽高,那么还是会调用onSizeReady() 方法。
重点线索就来到了onSIzeReady():
@Override
public synchronized void onSizeReady(int width, int height) {
//省略验证及其他代码
...
status = Status.RUNNING;
...
loadStatus =
engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);
...
}
很久没出现的engine出现了,作为引擎肯定是扮演驱动的角色,我们继续追踪其实现:
public synchronized <R> LoadStatus load(
...//省略各种参数
) {
...
//从内存或者缓存中查看是否有数据,假设我们第一次拿取数据,这些都为null
...
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache); //1
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob); //2
jobs.put(key, engineJob);
engineJob.addCallback(cb, callbackExecutor); //3
engineJob.start(decodeJob); //4
...
}
- 创建一个engineJob
- 创建一个decodeJob
- 给engineJob加两个回调(重点注意第一个cb)
- 开始执行Job
4、DecodeJob.run()
通过上面的分析,直接看engineJob.start(decodeJob):
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
//挑选一个线程池,然后执行 decodeJob,说明DecodeJob实现了Runnable接口,
//直接看DecodeJob 的run方法:
public void run() {
//省略验证及其他代码
...
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (CallbackException e) {
throw e;
} catch (Throwable t) {
...
} finally {
...
}
}
出去无关代码,来到runWrapped():
private void runWrapped() {
switch (runReason) { //1.最开始runReason == INITIALIZE
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
...
}
}
最开始runReason == INITIALIZE,我们继续看getNextStage(INITIALIZE):
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
...
}
}
diskCacheStrategy.decodeCachedResource()默认返回为true,所以返回的stage为Stage.RESOURCE_CACHE,接下来走getNextGenerator():
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
...
}
这一步是初始化currentGenerator,最后调用runGenerators():
private void runGenerators() {
...
boolean isStarted = false; //1
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) { //2
stage = getNextStage(stage); //3.1
currentGenerator = getNextGenerator(); //3.2
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
...
}
- 定义一个是否开始的flag。
- 正常情况下,如果没有调用cancel()方法,那么isCancelled == false,
currentGenerator在刚刚也初始化了,不可能为null,
最后调用currentGenerator.startNext():
public boolean startNext() {
//如果是第一次加载图片,那么sourceIds肯定没有,直接返回false
List<Key> sourceIds = helper.getCacheKeys();
if (sourceIds.isEmpty()) {
return false;
}
...
}
这行代码怎么理解呢?它要描述的意思很简单:
如果在正常的请求图片的流程中,存在一个currentGenerator,如果这个currentGenerator不能找到图片,就循环走3.1,3.2的流程,给下次阶段和currentGenerator赋值,然后再找图片。
根据这个思路,假设我们第一次加载图片,内存缓存中都没有图片,最后stage == Stage.SOURCE,currentGenerator == SourceGenerator(),接下里走SourceGenerator.startNext()(中间走了reschedule()方法赋值runReason,并无影响后面的流程)。
5、ModelLoader
接着上面,直接看SourceGenerator.startNext() 的实现:
@Override
public boolean startNext() {
//省略缓存相关代码
...
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) { //1
loadData = helper.getLoadData().get(loadDataListIndex++); //2
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
- 先看看
hasNextModelLoader()这个方
private boolean hasNextModelLoader() {
//loadDataListIndex 初始的时候为0
return loadDataListIndex < helper.getLoadData().size();
}
- 同样调用了
helper.getLoadData()
那么很负责任的告诉你们,本小小节的重点就在helper.getLoadData()这个方法上,而且也是解密上一章 .load(*) 凭什么传一个类型,就能找到对应的实现呢?
这里就不放源码了,调用关系略复杂,做的事情也比较简单,所以口述+部分关键源码展示:
还记得model这个东西嘛?当时我们调用 .load(*) 时,传入了String类型的图片的Url,这个url被保存为model,那么作为ModelLoader我们可以从名字上猜测,这个东西肯定是有关 .load(*) 各种重载方法的。helper.getLoadData()这个方法就是通过model的类型,找到对应的ModelLoader,而这些ModelLoader再最开始生成Glide实例的时候在其构造方法中被定义了:
//这些是String相关
registry.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
.append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
.append(
String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
//这些是Uri相关
.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
.append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(context.getAssets()))
//还有很多此处不一一例举,有File、Bitmap、Drawable等
append()方法有三个参数,第一个就是调用 .load(*) 时,*的类型;第二个就是数据加载后返回的类型;第三个就是具体的ModelLoader类。
因为我们传入的是String类型,那么得到的ModelLoader类一共有4个,除去中间会做一些判断筛选,还剩下三个,而这3个其实都是StringLoader,只不过该类中有三个内部工厂类,来生成差异化的StringLoader对象。
拿到ModelLoader集合后,通过其方法 buildLoadData(),将model转化成LoadData,而StringLoader的buildLoadData() 并不是直接返回LoadData,中间曲折最后调用了HttpGlideUrlLoader.buildLoadData():
@Override
public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
@NonNull Options options) {
GlideUrl url = model;
if (modelCache != null) {
url = modelCache.get(model, 0, 0);
if (url == null) {
modelCache.put(model, 0, 0, model);
url = model;
}
}
int timeout = options.get(TIMEOUT);
return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
拿到loadData后就可以请求数据了:loadData.fetcher.loadData(helper.getPriority(), this);
6、HttpUrlFetcher
loadData会使用fetcher来调用 loadData() 方法,而fetcher是个接口,具体是在HttpGlideUrlLoader中实现的,为HttpUrlFetcher:
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super InputStream> callback) {
...
try {
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException e) {
...
callback.onLoadFailed(e);
} finally {
...
}
}
看到这里就差不多了,loadDataWithRedirects() 这个方法就是网络请求数据的方法,里面的代码也不放出来了,就是普通的HttpURLConnection请求网络,然后返回一个输入流,这个流就是图片了。
然后在通过回调将数据传递到onDataReady() 方法中,这个方法在之前的SourceGenerator中有实现:
@Override
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
在这里会将dataToCache赋值,然后调用cb.reschedule();。
7、缓存
cb.reschedule();层层传递,又会回到自身调用startNext()(之前被隐藏的代码):
public boolean startNext() {
//之前dataToCache为null,所以没走这块
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
...
}
private void cacheData(Object dataToCache) {
...
try {
Encoder<Object> encoder = helper.getSourceEncoder(dataToCache); //1
DataCacheWriter<Object> writer =
new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
helper.getDiskCache().put(originalKey, writer); //2
...
} finally {
loadData.fetcher.cleanup();
}
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this); //3
}
这边是调用了cacheData() 来进行缓存图片的功能。
- 和之前找ModelLoader差不多,找解码器也是类似的,Glide在初始化的时候也会添加几个解码器,getSourceEncoder(*) 会根据传值的类型,来拿到Encoder,之前dataToCache是InputStream类型的,所以拿到的解码器是StreamEncoder
helper.getDiskCache()会拿到DiskLruCacheWrapper,然后进行LRU缓存。- 将**sourceCacheGenerator **初始化。
紧接着在startNext() 方法中会继续执行:
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
@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());
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);
}
}
return started;
}
8、加载图片
上面的操作是做了缓存,而显示图片其实是关键的一行代码:loadData.fetcher.loadData(helper.getPriority(), this);
其中loadData.fetcher是ByteBufferFileLoader,其方法源码:
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to obtain ByteBuffer for file", e);
}
callback.onLoadFailed(e);
return;
}
callback.onDataReady(result);
}
@Override
public void onDataReady(Object data) {
cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
}
然后又来到DecodeJob:
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
在这个方法中再次赋值runReason = RunReason.DECODE_DATA;并且调用callback.reschedule(this);再次回到最初的runWrapped() 方法中,走另一个分支:
private void runWrapped() {
switch (runReason) {
...
case DECODE_DATA:
decodeFromRetrievedData();
break;
...
}
}
在decodeFromRetrievedData方法中会进行解码,接着又会回调通知EnginJob来完成图片的加载,在EnginJob中关键的代码:
for (final ResourceCallbackAndExecutor entry : copy) {
entry.executor.execute(new CallResourceReady(entry.cb));
}
又是个线程池执行的方法,直接看CallResourceReady的run()方法:
@Override
public void run() {
synchronized (EngineJob.this) {
if (cbs.contains(cb)) {
engineResource.acquire();
callCallbackOnResourceReady(cb);
removeCallback(cb);
}
decrementPendingCallbacks();
}
}
}
@Synthetic
synchronized void callCallbackOnResourceReady(ResourceCallback cb) {
try {
cb.onResourceReady(engineResource, dataSource);
} catch (Throwable t) {
throw new CallbackException(t);
}
}
最后又回调了onResourceReady()方法,我们层层再找这个cb是哪个角色,原来是SingleRequest,再看看其方法实现,其中关键的又是调用了onResourceReady()方法:
private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
if (glideContext.getLogLevel() <= Log.DEBUG) {
Log.d(GLIDE_TAG, "Finished loading " + result.getClass().getSimpleName() + " from "
+ dataSource + " for " + model + " with size [" + width + "x" + height + "] in "
+ LogTime.getElapsedMillis(startTime) + " ms");
}
isCallingCallbacks = true;
try {
boolean anyListenerHandledUpdatingTarget = false;
if (requestListeners != null) {
for (RequestListener<R> listener : requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onResourceReady(result, model, target, dataSource, isFirstResource);
}
}
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
其中最重要的就是target.onResourceReady(result, animation);这行代码,还记得这个target是什么嘛?就是DrawableImageViewTarget,我们再去找他的实现:
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
就一行代码,终于将图片加载到ImageView上了!
总结
- 先创建好Target,这个target对象包含imageView的引用,图片的类型,还有一个Request(SingleRequest)。
- 创建Request,并且将其与Target绑定,这个Request是所有的请求,包含正常的图片请求、异常时的图片请求和缩略图请求。
- 将Target放入到管理生命周期相关的集合里,并且开始执行Request
- 创建一个EnginJob和一个DecodeJob。
- 在DecodeJob中会在缓存中拿去资源图片或者网络请求资源,然后对其缓存再解码。
- 最后层层回调,回到Request中使Target加载资源图片到ImageView上。
最后的个人总结
- 为什么会写这篇文章?
在2019年4月份的时候,我进了一个很小的公司,公司的前辈和我呆着仅仅4天的时间,他就离职了。在这期间他教过我如何如何提升自己,推荐了很多方法,比如说看郭霖老师的博客啊,还有玩Android网站啊,特别是他推荐看源码。
可是随着时间慢慢的推移,对于学习这方面,我仅仅是逛逛谷歌官网,学学Jetpack相关的东西啊,工作中遇到什么问题就去github ctrl c+v啊,使用这些东西十分的轻松,可这些都是很浅显的东西。
终于有一天,2019年12月份,我离开了上家公司,刚开始我很自信能够找到不错的工作,然而面试的过程中,当问到一些源码相关问题的时候,我总是以练懵逼或者含含糊糊的敷衍过去。
这些种种原因使得我想沉下心来,认认真真的分析一个三方框架的源码。 - 关于Glide
这篇系列文章并没有讲的很详细,因为Glide本身内容比较多,这篇系列文章只是辅助了解Glide,其中更多的内容,只能靠你们自行查阅源码,我相信这肯定是个很有趣的过程。
希望大家也能够从中学习到一些东西。 - 我的收获
一系列文章下来,我的个人总结能力提升不少,观看源码的能力也能够提升一点,那么我很自信在接下来的工作中,我能够很快的融入开发中。
这是我的第一个源码系列文章,是个很有里程碑纪念的意义,希望自己再接再厉,能够产出更多优质的文章,以供大家参考。
来源:CSDN
作者:catzifeng
链接:https://blog.csdn.net/catzifeng/article/details/104154916