glide 是目前android最广泛的图片加载框架之一,下面我们将分析其源码加载流程。
使用流程
glide 最基本的使用,如下,其他额外的功能,都是以建造者链式调用的基础上添加
Glide.with(context).load(url).into(targetView);
我们先通过艽野尘梦绘制的 glide 框架图来对 glide 总体有个初步了解
glide.with
看下 with 代码:
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getContext()).get(fragment);
}
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
....
return Glide.get(context).getRequestManagerRetriever();
}
可以看到 width的方法基本一致,都是通过 getRetriever 来获取到 RequestManagerRetriever 对象,然后再获取 RequestManager 对象并返回
Q: With() 的不同之处是什么呢,为什么要这样呢?
A:不同在于传入的参数不一致,可以是Context、Activity、Fragment等等。
因为 Glide 在加载图片的时候会绑定 with(context) 方法中传入的 context 的生命周期,如果传入的是 Activity ,那么在这个 Activity 销毁的时候 Glide 会停止图片的加载。这样避免了消耗多余的资源,也避免了在Activity销毁之后加载图片从而导致的空指针问题。
我们先 Glide.get(context):
public static Glide get(@NonNull Context context) {
if (glide == null) {
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) { // 初始化
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
private static void initializeGlide( // 创建 GlideBuilder @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
}
public final class GlideBuilder { // GlideBuilder 内容
private final Map, TransitionOptions, ?>> defaultTransitionOptions = new ArrayMap<>();
private Engine engine;
private BitmapPool bitmapPool;
private ArrayPool arrayPool;
private MemoryCache memoryCache;
private GlideExecutor sourceExecutor;
private GlideExecutor diskCacheExecutor;
private DiskCache.Factory diskCacheFactory;
private MemorySizeCalculator memorySizeCalculator;
private ConnectivityMonitorFactory connectivityMonitorFactory;
private int logLevel = Log.INFO;
private RequestOptionsFactory defaultRequestOptionsFactory =
new RequestOptionsFactory() {
@NonNull
@Override
public RequestOptions build() {
return new RequestOptions();
}
};
@Nullable private RequestManagerFactory requestManagerFactory;
private GlideExecutor animationExecutor;
private boolean isActiveResourceRetentionAllowed;
@Nullable private List> defaultRequestListeners;
private boolean isLoggingRequestOriginsEnabled;
private boolean isImageDecoderEnabledForBitmaps;
........
}
看到 glide.get(context)内容也挺多的,但是最重要的是创建了 glideBuilder 来配置,如图片内存缓存、本地缓存等等。开发者可以传入自主定义的配置
接下来,我们看 RequestManagerRetriever 中 get()
,同样该类 get() 也有几个:
// 根据传入不同的 Context ,获取不同的 RequestManager
public RequestManager get(@NonNull 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) {
return get((Activity) context);
} else if (context instanceof ContextWrapper
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
public RequestManager get(@NonNull FragmentActivity activity) { .........}public RequestManager get(@NonNull Fragment fragment){.......}
public RequestManager get(@NonNull Activity activity) {...........}
明显地看到,传入的 context 可以是 Application、FragmentActivity、Activity 或 ContextWrapper。
我们就拿其中一个来看,如传入 FragmentActivity ,代码如下所示:
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) { // 不是主线程
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity); // 判断最低版本、activity 是否销毁
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
代码逻辑很简单,看注释即可知道,我们看其中关键方法 supportFragmentGet()
:
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current = // 创建没有界面的 Fragment
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager); // Fragment 与 RequestManager 绑定,实现对 Activity 生命周期的监听
}
return requestManager;
}
with() 就已经结束完了,总结一下:
1. 通过 RequestManagerRetriever 的 get() 获取 RequestManagerRetriever 对象,然后再通过该对象 get(context)获取 RequestManager 对象
2. 获取 RequestManager 对象时,get(context) 传参不同,有不同的处理:
a. context 是 Application,通过 getApplicationManager(Context context) 创建并返回一个 RequestManager 对象
b. context 是 FragmentActivity,通过 supportFragmentGet( ) 在当前 activity 创建并添加一个没有界面的 fragment,从而实现图片加载与 activity 的生命周期相绑定,之后创建并返回一个 RequestManager 对象
load(url)
上面说到 with()返回一个 RequestManager 对象,我们在该对象中,看 load(url):
public RequestBuilder load(@Nullable String string) {
return asDrawable().load(string);
}
我们先看,asDrawable() :
public RequestBuilder asDrawable() {
return as(Drawable.class);
}
// 创建 一个 RequestBuilder 并返回
public RequestBuilder as(
@NonNull Class resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
明显地看到,asDrawable() 最终返回 RequestBuilder 对象,再结合 load(string):
public RequestBuilder load(@Nullable String string) {
return loadGeneric(string);
}
.......
private RequestBuilder loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
load() 只是把数据传入 RequestBuilder 中,并将数据源是否已设置标志位 isModelSet = true。
最重要的是 asDrawable 构建 RequestBuilder 对象,明显地,RequestBuilder 就是一个 builder 模式,我们平时的一些额外配置
,就是通过 Builder 模式配置的,如
Glide.with(context)
.load(url)
.placeholder(R.drawable.place_image)
.error(R.drawable.error_image)
.into(imageView);
// 源码在 RequestBuilder 的父类 BaseRequestOptions 中
public T error(@DrawableRes int resourceId) {
if (isAutoCloneEnabled) {
return clone().error(resourceId);
}
this.errorId = resourceId;
fields |= ERROR_ID;
this.errorPlaceholder = null;
fields &= ~ERROR_PLACEHOLDER;
return selfOrThrowIfLocked();
}
好,load(url) 已经分析完了,主要是构建一个 RequestBuilder 对象,配置图片加载的请求。
into (imageView)
上面说到了 load(url) 创建了一个 RequestBuilder,配置图片加载的请求,但也仅仅是个请求,并没有执行。真正的执行请求是在 into() 中,我们看下这个方法:
public ViewTarget into(@NonNull ImageView view) {
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:
}
}
return into(
// 根据 transcodeClass 类型不同 包装 view为 ViewTarget ,transcodeClass的值是 load(url)确定的
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null, // targetListener 监听图片加载是否成功
requestOptions,
Executors.mainThreadExecutor()); // 调用 execute 在主线程执行任务
}
.....
private > Y into(
@NonNull Y target,
@Nullable RequestListener targetListener,
BaseRequestOptions> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//创建当前 request,Request 是一个接口,我们获得的是 SingleRequest
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous) // 当前与上一个是否相同
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
requestManager.clear(target); // 清除 previous,防止重用,出现错位或闪烁
target.setRequest(request); // ViewTarget 与 请求绑定
requestManager.track(target, request); // 执行 request
return target;
}
// 我们看 track()
synchronized void track(@NonNull Target> target, @NonNull Request request) {
targetTracker.track(target); //监听 viewTarget 生命周期
requestTracker.runRequest(request); // 执行请求
}
// 再看 runRequest ()
public void runRequest(@NonNull Request request) {
requests.add(request);//加入请求列表中
if (!isPaused) {
request.begin(); // 非暂停状态,开始执行请求
} else {
request.clear();
pendingRequests.add(request); // 暂停状态下,加入等待列表中
}
}
前面说了 request 是一个接口,我们获取到的是 SingleRequest,接着我们看该类里面的 begin()
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) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
// Restarts for requests that are neither complete nor running can be treated as new requests
// and can run again from the beginning.
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight); // 尺寸已确定,准备执行请求
} else {
target.getSize(this); // 获取尺寸,然后再次调用 onSizeReady
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable()); // 开始加载,先显示占位图
}
}
}
// 接下来,看 onSizeReady() 如何请求图片
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
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);
if (status != Status.RUNNING) {
loadStatus = null;
}
}
我们来看下 load 内部的实现:
public LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class> resourceClass,
Class transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map, Transformation>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
EngineResource> memoryResource;
synchronized (this) {
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);
}
}
//拿到图片后的操作
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
看到,先从缓存中拉取,没有再去网络中请求,暂且不看网络是如何请求的,看下拿到图片后的操作 cb.onResourceReady()
:
public void onResourceReady(Resource> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
Resource> toRelease = null;
try {
synchronized (requestLock) {
if (resource == null) {
GlideException exception =
new GlideException(
"Expected to receive a Resource with an "
+ "object of "
+ transcodeClass
+ " inside, but instead got null.");
onLoadFailed(exception); //回调失败
return;
}
.....
Object received = resource.get();
......
onResourceReady((Resource) resource, (R) received, dataSource); // 成功后的处理
}
} finally {
if (toRelease != null) {
engine.release(toRelease);
}
}
}
......
private void onResourceReady(Resource resource, R result, DataSource dataSource) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
isCallingCallbacks = true;
try {
boolean anyListenerHandledUpdatingTarget = false;
if (requestListeners != null) {
for (RequestListener listener : requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onResourceReady(result, model, target, dataSource, isFirstResource);
}
}
......
if (!anyListenerHandledUpdatingTarget) {
Transition super R> animation = animationFactory.build(dataSource, isFirstResource);
target.onResourceReady(result, animation); // 最终 view.setImageBitmap(resource);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
获取图片后,还是一步一步到 setResource(),最后调用常用的图片加载方法
into() 基本分析完了,暂且忽略了网络请求图片部分(过于复杂,下次再分析),总结一下:
将 view 包装成 viewTarget
创建一个 SingleRequest ,包含了请求的信息
清除这个 viewTarget 之前绑定的请求,绑定新的请求
执行新的请求,先查缓存,没有再去网络请求
获取图片数据之后,成功则会调用notifyLoadSuccess()并设置 setImagexxx,失败则onLoadFailed()和显示获取失败占位图
参考
Glide源码分析
Android主流三方库源码分析(三、深入理解Glide源码)