Glide 内部获取图片主要工作
into 调用
- 收到加载请求
- 看内存缓存(active、cache),磁盘缓存有没有,有就直接回调回去
- 没有就网络请求
- 请求回来就构建资源、缓存
- 最终回到 DrawableImageViewTarget
活动图
源码分析
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
// 构建 BaseRequestOptions,根据不同的裁切类型配置
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
// 在 buildImageViewTarget 后,重载 into 方法
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/* targetListener= */ null,
requestOptions,
Executors.mainThreadExecutor());
}
// 先看看 buildImageViewTarget,根据之前asBitmap 还是 asDrawable 创建 BitmapImageViewTarget 或 DrawableImageViewTarget
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
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)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
// 看一下 DrawableImageViewTarget
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
public DrawableImageViewTarget(ImageView view) {
super(view);
}
/**
* @deprecated Use {@link #waitForLayout()} instead.
*/
// Public API.
@SuppressWarnings({"unused", "deprecation"})
@Deprecated
public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
super(view, waitForLayout);
}
@Override
protected void setResource(@Nullable Drawable resource) {
// 最终设置图片的地方
view.setImageDrawable(resource);
}
}
// 再看 into 方法
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
//这里的 isModelSet 是在 load 的时候赋值为 true 的,所以不会抛异常
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//为这个 http://xxx.png 生成一个 Glide request 请求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//相当于拿到上一个请求
Request previous = target.getRequest();
//下面的几行说明是否与上一个请求冲突,一般不用管 直接看下面 else 判断
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
//清理掉目标请求管理
requestManager.clear(target);
//重新为目标设置一个 Glide request 请求
target.setRequest(request);
//最后是调用 RequestManager 的 track 来执行目标的 Glide request 请求
requestManager.track(target, request);
return target;
}
// buildRequest 支线 --> obtainRequest --> 再到 new SingleRequest
// 继续跟进
// note jin: 这里对当前 class 加了一个同步锁避免线程引起的安全性
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
//添加一个目标任务
targetTracker.track(target);
//执行 Glide request
requestTracker.runRequest(request);
}
public void runRequest(@NonNull Request request) {
//添加一个请求
requests.add(request);
if (!isPaused) {
//没有暂停,开始调用 Request begin 执行
request.begin();
} else {
//如果调用了 暂停,清理请求
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
// 跟进 SingleRequest 的 begin
@Override
public void begin() {
synchronized (requestLock) {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
//检查外部调用的尺寸是否有效
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
//失败的回调
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
// starting the new load.
if (status == Status.COMPLETE) {
// note jin: 表示资源准备好了
onResourceReady(
resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
return;
}
experimentalNotifyRequestStarted(model);
cookie = GlideTrace.beginSectionAsync(TAG);
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// note jin: 这里表示大小已经准备好了
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
// note jin: 这里是刚刚开始执行的回调,相当于显示开始的进度
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
}
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
……
// note jin: //加载
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);
……
}
}
public <R> LoadStatus load(
GlideContext glideContext,
Object model, …… ) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
// note jin: //拿到缓存或者请求的 key
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
// note jin: //根据 key 拿到内存缓存中的资源
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
// note jin: //如果 memoryResource 内存缓存中有就回调出去
cb.onResourceReady(
memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
return null;
}
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return active;
}
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
}
return null;
}
private <R> LoadStatus waitForExistingOrStartNewJob(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
……) {
// note jin: 根据 Key 看看缓存中是否正在执行
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
// note jin: //如果正在执行,把数据回调出去
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
// note jin: 构建新的请求任务
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
// note jin: //把当前需要执行的 key 添加进缓存
jobs.put(key, engineJob);
// note jin: //执行任务的回调
engineJob.addCallback(cb, callbackExecutor);
// note jin: //开始执行
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
// 最后走进DecodeJob 的 run
public void run() {
// This should be much more fine grained, but since Java's thread pool implementation silently
// swallows all otherwise fatal exceptions, this will at least make it obvious to developers
// that something is failing.
GlideTrace.beginSectionFormat("DecodeJob#run(reason=%s, model=%s)", runReason, model);
// Methods in the try statement can invalidate currentFetcher, so set a local variable here to
// ensure that the fetcher is cleaned up either way.
DataFetcher<?> localFetcher = currentFetcher;
try {
//是否取消了当前请求
if (isCancelled) {
notifyFailed();
return;
}
//执行
runWrapped();
} catch (CallbackException e) {
// If a callback not controlled by Glide throws an exception, we should avoid the Glide
// specific debug logic below.
throw e;
} catch (Throwable t) {
// Catch Throwable and not Exception to handle OOMs. Throwables are swallowed by our
// usage of .submit() in GlideExecutor so we're not silently hiding crashes by doing this. We
// are however ensuring that our callbacks are always notified when a load fails. Without this
// notification, uncaught throwables never notify the corresponding callbacks, which can cause
// loads to silently hang forever, a case that's especially bad for users using Futures on
// background threads.
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(
TAG,
"DecodeJob threw unexpectedly" + ", isCancelled: " + isCancelled + ", stage: " + stage,
t);
}
// When we're encoding we've already notified our callback and it isn't safe to do so again.
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
throw t;
} finally {
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//获取资源状态
stage = getNextStage(Stage.INITIALIZE);
//根据当前资源状态,获取资源执行器
currentGenerator = getNextGenerator();
//执行
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//判断是否取消,是否开始
//调用 DataFetcherGenerator.startNext() 判断是否是属于开始执行的任务
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule(RunReason.SWITCH_TO_SOURCE_SERVICE);
return;
}
}
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
try {
boolean isDataInCache = cacheData(data);
// If we failed to write the data to cache, the cacheData method will try to decode the
// original data directly instead of going through the disk cache. Since cacheData has
// already called our callback at this point, there's nothing more to do but return.
if (!isDataInCache) {
return true;
}
// If we were able to write the data to cache successfully, we now need to proceed to call
// the sourceCacheGenerator below to load the data from cache.
} catch (IOException e) {
// An IOException means we weren't able to write data to cache or we weren't able to rewind
// it after a disk cache write failed. In either case we can just move on and try the next
// fetch below.
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to properly rewind or write data to cache", e);
}
}
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
//获取一个 ModelLoad 加载器
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//使用加载器中的 fetcher 根据优先级加载数据
startNextLoad(loadData);
}
}
return started;
}
private void startNextLoad(final LoadData<?> toStart) {
//通过拿到的加载器,开始加载数据
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {
@Override
public void onDataReady(@Nullable Object data) {
if (isCurrentRequest(toStart)) {
onDataReadyInternal(toStart, data);
}
}
@Override
public void onLoadFailed(@NonNull Exception e) {
if (isCurrentRequest(toStart)) {
onLoadFailedInternal(toStart, e);
}
}
});
}
// loadData 真正加载数据,获取后 回调到 onDataReadyInternal
public void loadData(
@NonNull Priority priority, @NonNull final DataCallback<? super InputStream> callback) {
Request.Builder requestBuilder = new Request.Builder().url(url.toStringUrl());
for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
String key = headerEntry.getKey();
requestBuilder.addHeader(key, headerEntry.getValue());
}
Request request = requestBuilder.build();
this.callback = callback;
call = client.newCall(request);
call.enqueue(this);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
responseBody = response.body();
if (response.isSuccessful()) {
long contentLength = Preconditions.checkNotNull(responseBody).contentLength();
stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);
callback.onDataReady(stream);
} else {
callback.onLoadFailed(new HttpException(response.message(), response.code()));
}
}
@Synthetic
void onDataReadyInternal(LoadData<?> loadData, 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);
}
}
@Override
public void onDataFetcherReady(
Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey; //当前返回数据的 key
this.currentData = data; //返回的数据
this.currentFetcher = fetcher; //返回的数据执行器,这里可以理解为 OkHttpStreamFetcher
this.currentDataSource = dataSource; //数据来源 url
this.currentAttemptingKey = attemptedKey;
this.isLoadingFromAlternateCacheKey = sourceKey != decodeHelper.getCacheKeys().get(0);
if (Thread.currentThread() != currentThread) {
reschedule(RunReason.DECODE_DATA);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
// 解析返回回来的数据
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
// 调用 decodeFrom 解析 数据;HttpUrlFetcher , InputStream ,currentDataSource
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
//解析完成后,通知下去
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource, isLoadingFromAlternateCacheKey);
} else {
runGenerators();
}
}
// decodeFromData --> DecodePath.decode
分了三大步
decodeResource
onResourceDecoded
BitmapDrawableTranscoder.transcode
decodeResource: 解码图片资源,将其转换为 Bitmap 对象。
onResourceDecoded: 对解码后的 Bitmap 进行可能的额外处理。
BitmapDrawableTranscoder.transcode: 将 Bitmap 转换为 Drawable 对象,以便在 ImageView 中显示。
// 执行完 decodeFromData,接下来 notifyEncodeAndRelease
private void notifyComplete(
Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource, isLoadedFromAlternateCacheKey);
}
@Override
public void onResourceReady(
Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
this.isLoadedFromAlternateCacheKey = isLoadedFromAlternateCacheKey;
}
notifyCallbacksOfResult();
}
@Synthetic
void notifyCallbacksOfResult() {
……
// note jin: 回调上层 Engine 任务完成了
engineJobListener.onEngineJobComplete(this, localKey, localResource);
//遍历资源回调给 ImageViewTarget
for (final ResourceCallbackAndExecutor entry : copy) {
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
// CallResourceReady.run
@Override
public void run() {
synchronized (cb.getLock()) {
synchronized (EngineJob.this) {
if (cbs.contains(cb)) {
// Acquire for this particular callback.
engineResource.acquire();
//返回准备好的资源
callCallbackOnResourceReady(cb);
removeCallback(cb);
}
decrementPendingCallbacks();
}
}
}
// callCallbackOnResourceReady --> SingleRequest#onResourceReady
private void onResourceReady(
Resource<R> resource, R result, DataSource dataSource, boolean isAlternateCacheKey) {
try {
if (!anyListenerHandledUpdatingTarget) {
// note jin: 回调给目标 ImageViewTarget 资源准备好了
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
GlideTrace.endSectionAsync(TAG, cookie);
}
// target 就是 ImageViewTarget
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
private void setResourceInternal(@Nullable Z resource) {
setResource(resource);
maybeUpdateAnimatable(resource);
}
// setResource 实现在 DrawableImageViewTarget#setResource
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
到这一步,真正把 Drawable 资源 设置到 view 里面,图片展示