总体设计图
1. Glide with
glide with 是用于glide初始化。
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
@Deprecated
@NonNull
public static RequestManager with(@NonNull android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
@NonNull
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
glide with有很多不同参数类型的方法,但是这些参数都是为了将 Context 传递下去,在后面的分析可以看到,紧接着我们分析一下 getRetriever
private static void initializeGlide(@NonNull Context context) {
// 初始化Glide
initializeGlide(context, new GlideBuilder());
}
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
manifestModules = new ManifestParser(applicationContext).parse();
}
if (annotationGeneratedModule != null
&& !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
Set<Class<?>> excludedModuleClasses =
annotationGeneratedModule.getExcludedModuleClasses();
Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
while (iterator.hasNext()) {
com.bumptech.glide.module.GlideModule current = iterator.next();
if (!excludedModuleClasses.contains(current.getClass())) {
continue;
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
}
iterator.remove();
}
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
}
}
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
builder.setRequestManagerFactory(factory);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
Glide glide = builder.build(applicationContext);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.registerComponents(applicationContext, glide, glide.registry);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
}
getRetriever 会调用到 glide 的初始化方法, initializeGlide()
new GlideBuilder()- 反射获取
GeneratedAppGlideModuleImpl实例,此类为设置扩展配置@GlideModule时自动生成的类 。4.0提高glide初始化速度,可以禁用清单解析,覆盖AppGlideModule实现中的isManifestParsingEnabled返回 false。 - 兼容3.0行为,
new ManifestParser(applicationContext).parse();获取 Manifest 内声明的 GlideModule ,并调用每个 module 的相关方法applyOptions registerComponents,实现扩展。 - 通过
GlideBuilder创建 Glide 实例,Glide类中实现了ComponentCallbacks2接口,通过applicationContext.registerComponentCallbacks(glide);进行注册,监听应用的 onLowMemory 与 onTrimMemory ,在 lowMemory 时进行清理缓存,在 onTrimMemory 的回调中,根据不同的 level 进行缓存清理 - 拿取 glide 中的
requestManagerRetriever对象
//RequestManagerRetriever
@NonNull
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) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
@NonNull
public RequestManager get(@NonNull Fragment fragment) {
Preconditions.checkNotNull(fragment.getActivity(),
"You cannot start a load on a fragment before it is attached or after it is destroyed");
if (Util.isOnBackgroundThread()) {
return get(fragment.getActivity().getApplicationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
}
}
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
上诉get方法,总结起来就是,如果不在主线程,就使用ApplicationContext,否则就使用自己本身的context
@NonNull
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
区分 context 的原因是因为需要通过 context 判断,是否需要创建 SupportRequestManagerFragment ,此 Fragment 为空界面 Fragment,可以看到上诉两个方法创建 RequestManager 对象不同之处在于,是否与 Fragment 进行绑定,如果需要创建 Fragment 则使用 current.getGlideLifecycle() , current.getRequestManagerTreeNode()否则使用的是 new ApplicationLifecycle(), new EmptyRequestManagerTreeNode()
//RequestManager
/**
* Lifecycle callback that registers for connectivity events (if the
* android.permission.ACCESS_NETWORK_STATE permission is present) and restarts failed or paused
* requests.
*/
@Override
public synchronized void onStart() {
resumeRequests();
targetTracker.onStart();
}
/**
* Lifecycle callback that unregisters for connectivity events (if the
* android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
*/
@Override
public synchronized void onStop() {
pauseRequests();
targetTracker.onStop();
}
/**
* Lifecycle callback that cancels all in progress requests and clears and recycles resources for
* all completed requests.
*/
@Override
public synchronized void onDestroy() {
targetTracker.onDestroy();
for (Target<?> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();
requestTracker.clearRequests();
lifecycle.removeListener(this);
lifecycle.removeListener(connectivityMonitor);
mainHandler.removeCallbacks(addSelfToLifecycle);
glide.unregisterRequestManager(this);
}
private class RequestManagerConnectivityListener
implements ConnectivityMonitor.ConnectivityListener {
@GuardedBy("RequestManager.this")
private final RequestTracker requestTracker;
RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) {
this.requestTracker = requestTracker;
}
@Override
public void onConnectivityChanged(boolean isConnected) {
if (isConnected) {
synchronized (RequestManager.this) {
requestTracker.restartRequests();
}
}
}
}
glide 需要监听 LifecycleListener 的原因是,通过生命周期来管控 requests 的行为,除了生命周期,还会默认去通过监听网络状态来进行管理,这里的 context 区别就出来了,如果是 fragment 的生命周期,那么当fragment 所在的activity 销毁时,requst 的行为就停止了。
这里要注意两个类,ActivityFragmentLifecycle 与 ApplicationLifecycle ,Glide并不是通过 android 的真正的 Lifecycle 来进行的监听,而是自己封装了一套自己的 Lifecycle ,ActivityFragmentLifecycle 中维护了Set 来管理所有的 lifecycleListeners,而 ApplicationLifecycle 里仅仅只有 listener.onStart() 使用。所以在使用Glide的时候, 如果在主线程,尽量不要图省事使用Application的Context。
2. Glide load
//RequestManager
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
//RequestBuilder
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
glide 4.0 的 load 没有什么特别的东西了。
- 创建了
RequestBuilder对象 - 进行一个赋值操作,对
isModelSet标识位进行一个赋值,这个值会在 into 中用到。
但是这里有一个链式调用的小技巧吧,一般情况下,我们写代码的时候是不加 asXXX() 方法的,可以看到
RequestManager 与 RequestBuilder 都有一个load方法,返回的都是 RequestBuilder ,这里其实就是为了书写的方便,RequestBuilder 其实是通过 asXXX() 方法生成,为了可以隐藏 asXXX() 方法,便在两个类用相同的方法名。这样我们写代码的时候 Glide.with(context).asDrawable().load() 可以写成 Glide.with(context).load() ,使用不同的asXXX() 也不会打乱 调用的顺序。
3. Glide into
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
//RequestBuilder
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don't retain the transformation applied based on the previous
// View's scale type.
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.
}
}
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
先获取 ImageView 的缩放状态,然后深拷贝 requestOptions 将缩放状态添加进去,使用深拷贝的原因是使用相同的 RequestBuilder 放入不同的 ImageView 中,不会受到缩放状态的影响。
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
//ImageViewTargetFactory
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
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)");
}
}
}
glideContext.buildImageViewTarget(view, transcodeClass) 通过 asXXX 里传递的参数 创建不同的 ViewTarget,为兼容不同的资源 Bitmap 与 Drawable
Gif 比较特殊,Glide 自己写了一个类 GifDrawable 继承 Drawable ,至于是如何加载可播放的gif 暂不分析(其实是还没看懂)
//RequestBuilder
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
//ViewTarget
@Override
public void setRequest(@Nullable Request request) {
setTag(request);
}
@Override
@Nullable
public Request getRequest() {
Object tag = getTag();
Request request = null;
if (tag != null) {
if (tag instanceof Request) {
request = (Request) tag;
} else {
throw new IllegalArgumentException(
"You must not call setTag() on a view Glide is targeting");
}
}
return request;
}
进入 into 源码,首先会对 isModelSet 进行判断,是否 load 在 into 之前调用了。into 中会创建 request 对象,glide 通过 view.setTag 来为每一个view设置自己独有的 request.所以这也是为什么在使用 glide 加载图片的时候,不能再去使用 setTag 的方法。然后通过 requestManager.track 来开始 request
流程:
- 判断是否调用 load
- 创建request对象,并通过
view.setTag储存 - 通过
requestManager.track来开始request.
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
private Request buildRequestRecursive(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
Request mainRequest =
buildThumbnailRequestRecursive(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
if (errorRequestCoordinator == null) {
return mainRequest;
}
int errorOverrideWidth = errorBuilder.getOverrideWidth();
int errorOverrideHeight = errorBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !errorBuilder.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
Request errorRequest =
errorBuilder.buildRequestRecursive(
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder,
callbackExecutor);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
private Request buildThumbnailRequestRecursive(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
if (thumbnailBuilder != null) {
// Recursive case: contains a potentially recursive thumbnail request builder.
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()");
}
TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
thumbnailBuilder.transitionOptions;
// Apply our transition by default to thumbnail requests but avoid overriding custom options
// that may have been applied on the thumbnail request explicitly.
if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
thumbTransitionOptions = transitionOptions;
}
Priority thumbPriority = thumbnailBuilder.isPrioritySet()
? thumbnailBuilder.getPriority() : getThumbnailPriority(priority);
int thumbOverrideWidth = thumbnailBuilder.getOverrideWidth();
int thumbOverrideHeight = thumbnailBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !thumbnailBuilder.isValidOverride()) {
thumbOverrideWidth = requestOptions.getOverrideWidth();
thumbOverrideHeight = requestOptions.getOverrideHeight();
}
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest =
obtainRequest(
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(
target,
targetListener,
coordinator,
thumbTransitionOptions,
thumbPriority,
thumbOverrideWidth,
thumbOverrideHeight,
thumbnailBuilder,
callbackExecutor);
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,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
BaseRequestOptions<?> thumbnailOptions =
requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
Request thumbnailRequest =
obtainRequest(
target,
targetListener,
thumbnailOptions,
coordinator,
transitionOptions,
getThumbnailPriority(priority),
overrideWidth,
overrideHeight,
callbackExecutor);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// Base case: no thumbnail.
return obtainRequest(
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
private Request obtainRequest(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
这里可以看到,buildRequest() 方法的内部其实又调用了 buildRequestRecursive() 方法,而buildRequestRecursive() 方法中的代码主要都是在处理缩略图的,可以看到在有 error 的时候会创建2个 request ,如果是单一request 会通过 SingleRequest.obtain 来创建,如果是多个则会创建 ThumbnailRequestCoordinator, 将每个通过 SingleRequest.obtain 创建的 request 添加进去 ,ThumbnailRequestCoordinator 其实只是封装了多个 request 的处理逻辑 。
public static <R> SingleRequest<R> obtain(
Context context,
GlideContext glideContext,
Object model,
Class<R> transcodeClass,
BaseRequestOptions<?> requestOptions,
int overrideWidth,
int overrideHeight,
Priority priority,
Target<R> target,
RequestListener<R> targetListener,
@Nullable List<RequestListener<R>> requestListeners,
RequestCoordinator requestCoordinator,
Engine engine,
TransitionFactory<? super R> animationFactory,
Executor callbackExecutor) {
@SuppressWarnings("unchecked") SingleRequest<R> request =
(SingleRequest<R>) POOL.acquire();
if (request == null) {
request = new SingleRequest<>();
}
request.init(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
engine,
animationFactory,
callbackExecutor);
return request;
}
private synchronized void init(
Context context,
GlideContext glideContext,
Object model,
Class<R> transcodeClass,
BaseRequestOptions<?> requestOptions,
int overrideWidth,
int overrideHeight,
Priority priority,
Target<R> target,
RequestListener<R> targetListener,
@Nullable List<RequestListener<R>> requestListeners,
RequestCoordinator requestCoordinator,
Engine engine,
TransitionFactory<? super R> animationFactory,
Executor callbackExecutor) {
this.context = context;
this.glideContext = glideContext;
this.model = model;
this.transcodeClass = transcodeClass;
this.requestOptions = requestOptions;
this.overrideWidth = overrideWidth;
this.overrideHeight = overrideHeight;
this.priority = priority;
this.target = target;
this.targetListener = targetListener;
this.requestListeners = requestListeners;
this.requestCoordinator = requestCoordinator;
this.engine = engine;
this.animationFactory = animationFactory;
this.callbackExecutor = callbackExecutor;
status = Status.PENDING;
if (requestOrigin == null && glideContext.isLoggingRequestOriginsEnabled()) {
requestOrigin = new RuntimeException("Glide request origin trace");
}
}
创建 request 对象 ,其实只是将之前glide的那些配置全部传入 request 中,对这些变量进行赋值。创建 request 对象就结束了,紧接着回到之前说的 request 的运行,可以看到 request 是通过 requestManager.track(target, request); 运行的
//RequestManager
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
//RequestTracker
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);
}
}
之前分析可知,request 的实现实际为 SingleRequest ,这里 run 的逻辑较为简单,通过 request 的生命周期进行判断当前 request 的行为 , 继续跟进 begin 的实现。
//SingleRequest
@Override
public synchronized void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
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");
}
// If we're restarted after we're complete (usually via something like a notifyDataSetChanged
// that starts an identical request into the same Target or View), we can simply use the
// resource and size we retrieved the last time around and skip obtaining a new size, starting a
// new load etc. This does mean that users who want to restart a load because they expect that
// the view size has changed will need to explicitly clear the View or Target before 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);
}
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));
}
}
首先当 model 为 null 也就是 load 传入的 url 为 null 的时候,会去调用 onLoadFailed , 并且通过是否有 后备占位图 来定义 log 的级别。先分析 onLoadFailed
//SingleRequest
private synchronized void onLoadFailed(GlideException e, int maxLogLevel) {
stateVerifier.throwIfRecycled();
e.setOrigin(requestOrigin);
int logLevel = glideContext.getLogLevel();
if (logLevel <= maxLogLevel) {
Log.w(GLIDE_TAG, "Load failed for " + model + " with size [" + width + "x" + height + "]", e);
if (logLevel <= Log.INFO) {
e.logRootCauses(GLIDE_TAG);
}
}
loadStatus = null;
status = Status.FAILED;
isCallingCallbacks = true;
try {
//TODO: what if this is a thumbnail request?
boolean anyListenerHandledUpdatingTarget = false;
if (requestListeners != null) {
for (RequestListener<R> listener : requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onLoadFailed(e, model, target, isFirstReadyResource());
}
}
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onLoadFailed(e, model, target, isFirstReadyResource());
if (!anyListenerHandledUpdatingTarget) {
setErrorPlaceholder();
}
} finally {
isCallingCallbacks = false;
}
notifyLoadFailed();
}
private synchronized void setErrorPlaceholder() {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = null;
if (model == null) {
error = getFallbackDrawable();
}
if (error == null) {
error = getErrorDrawable();
}
if (error == null) {
error = getPlaceholderDrawable();
}
target.onLoadFailed(error);
}
//ImageViewTarget
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
setResourceInternal(null);
setDrawable(errorDrawable);
}
onLoadFailed 中 会调用到 setErrorPlaceholder ,而 setErrorPlaceholder 中 会依次获取 不同类型的占位图 ,最后设置到 view 中。
- placeholder Drawable是当请求正在执行时被展示的 Drawable
- error Drawable 在请求永久性失败时展示
- fallback Drawable 在请求的url/model为 null 时展示 ,例如头像为null时的场景
回到 begin
如果在之前调用了指定override()的宽高就直接调用onSizeReady,否则调用target.getSize(this)获取图片宽高后,再调用onSizeReady, 最后都会调用到 onSizeReady 方法
//SingleRequest
@Override
public synchronized void onSizeReady(int width, int height) {
//如果对象可回收(即当前在对象池中),则抛出一个异常。
stateVerifier.throwIfRecycled();
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
//加载尺寸为 View 或 Target 的某个百分比的图片,默认为1
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (IS_VERBOSE_LOGGABLE) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
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;
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
//GlideBuilder
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}
onSizeReady 中会调用 engine.load ,而 engine 是在 glideBuilder 中 build 时 ,将 下载方面的对象传入。
//Engine.java
public synchronized <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
// 根据key,检查当前使用的资源,并返回当前的活跃资源,从Map中取出
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
// 从MemoryCache(接口) 中取出, 默认为glide的 LruResourceCache ,使用LinkedHashMap实现的LRU算法
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
// 检查当前的加载进度,并将cb添加到正在进行的加载进度中
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
// 构建了一个EngineJob,它的主要作用就是用来开启线程的
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
// 构建了一个 DecodeJob ,为图片解码
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb, callbackExecutor);
//运行job
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
// 开始一个新的加载
return new LoadStatus(cb, engineJob);
}
所有的请求流程都如下:
- 根据key,检查当前使用的资源,并返回当前的活跃资源,从Map中取出
- 从MemoryCache(接口) 中取出, 默认为glide的 LruResourceCache ,使用LinkedHashMap实现的LRU算法
- 检查当前的加载进度,并将cb添加到正在进行的加载进度中
- 创建2个job,并运行
- 开始一个新的加载
//EngineJob.java
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
//GlideExecutor.java
@Override
public void execute(@NonNull Runnable command) {
delegate.execute(command);
}
此处分为2种情况,一种是从磁盘中获取,一种是从网络获取,然后开启线程池,在子线程中处理获取图片逻辑。所以回到 DecodeJob的 run 方法中
//DecodeJob.java
@Override
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
//主要方法
runWrapped();
} catch (Throwable t) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "DecodeJob threw unexpectedly"
+ ", isCancelled: " + isCancelled
+ ", stage: " + stage, t);
}
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
} finally {
// Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
// close in all cases anyway.
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//初始化 获取下一个阶段状态
stage = getNextStage(Stage.INITIALIZE);
//获取当前 “Generator”(发电机?)
currentGenerator = getNextGenerator();
//运行 load数据
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
//处理已经load到的数据
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
先看一下runGenerators方法
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
// 获取下一次阶段 ,根据stage 获取 Generator
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
private Stage getNextStage(Stage current) {
switch (current) {
//根据定义的缓存策略来取下一个状态
//缓存策略来之于RequestBuilder的requestOptions域
//如果你有自定义的策略,可以调用RequestBuilder.apply方法即可
//详细的可用缓存策略请参看DiskCacheStrategy.java
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
return Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
getNextStage:
获取下一步执行的策略,一共5种策略:INITIALIZE,RESOURCE_CACHE,DATA_CACHE,SOURCE,FINISHED
其中加载数据的策略有三种:RESOURCE_CACHE,DATA_CACHE,SOURCE,分别对应的Generator:
- ResourceCacheGenerator :尝试从修改过的资源缓存中获取,如果缓存未命中,尝试从DATA_CACHE中获取
- DataCacheGenerator 尝试从未修改过的本地缓存中获取数据,如果缓存未命中则尝试从SourceGenerator中获取
- SourceGenerator 从原始的资源中获取,可能是服务器,也可能是本地的一些原始资源策略的配置在DiskCacheStrategy。开发者可通过BaseRequestOptions设置:
- ALL
- NONE
- DATA
- RESOURCE
- AUTOMATIC(默认方式,依赖于DataFetcher的数据源和ResourceEncoder的EncodeStrategy)
getNextGenerator:
根据Stage获取到相应的Generator后会执行currentGenerator.startNext(),如果中途startNext返回true,则直接回调,否则最终会得到SOURCE的stage,重新调度任务
因为上诉为while循环,stage 一步步下去最后的是 SOURCE , 也就是说最后总会调用到 SourceGenerator.startNext
//SourceGenerator.java
@Override
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
////查找ModelLoader
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
////根据model的fetcher加载数据
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
//DataCacheGenerator
@Override
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
Key sourceId = cacheKeys.get(sourceIdIndex);
// PMD.AvoidInstantiatingObjectsInLoops The loop iterates a limited number of times
// and the actions it performs are much more expensive than a single allocation.
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
//获取缓存文件
cacheFile = helper.getDiskCache().get(originalKey);
if (cacheFile != null) {
this.sourceKey = sourceId;
//通过DecodeHelper 获取ModelLoader
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;
}
modelLoaders是通过glideContext.getRegistry().getModelLoaders(file)获取。
其中Registry在Glide的构造方法中创建的,并且注册了许多解析器,ByteBufferEncoder,BitmapDrawableDecoder等等,我们只关注 .append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
//Glide
registry
.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
//Registry
@NonNull
public <Model, Data> Registry append(
@NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass,
@NonNull ModelLoaderFactory<Model, Data> factory) {
modelLoaderRegistry.append(modelClass, dataClass, factory);
return this;
}
//ModelLoaderRegistry
public synchronized <Model, Data> void append(
@NonNull Class<Model> modelClass,
@NonNull Class<Data> dataClass,
@NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
multiModelLoaderFactory.append(modelClass, dataClass, factory);
cache.clear();
}
//MultiModelLoaderFactory
synchronized <Model, Data> void append(
@NonNull Class<Model> modelClass,
@NonNull Class<Data> dataClass,
@NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
add(modelClass, dataClass, factory, /*append=*/ true);
}
private <Model, Data> void add(
@NonNull Class<Model> modelClass,
@NonNull Class<Data> dataClass,
@NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory,
boolean append) {
Entry<Model, Data> entry = new Entry<>(modelClass, dataClass, factory);
entries.add(append ? entries.size() : 0, entry);
}
这里add主要是创建了一个Entry对象,把我们的modelClass,dataClass和factory对象关联起来,然后存放到entries的list集合中,这个Entry对象的理解关系到我们后面对整个网络加载的流程。
我们继续看刚才的getModelLoaders(cacheFile)
//Registry
@NonNull
public <Model> List<ModelLoader<Model, ?>> getModelLoaders(@NonNull Model model) {
//获取 modelLoaders 集合
List<ModelLoader<Model, ?>> result = modelLoaderRegistry.getModelLoaders(model);
if (result.isEmpty()) {
throw new NoModelLoaderAvailableException(model);
}
return result;
}
//ModelLoaderRegistry
@NonNull
public synchronized <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
int size = modelLoaders.size();
List<ModelLoader<A, ?>> filteredLoaders = new ArrayList<>(size);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0; i < size; i++) {
ModelLoader<A, ?> loader = modelLoaders.get(i);
if (loader.handles(model)) {
filteredLoaders.add(loader);
}
}
return filteredLoaders;
}
@NonNull
private <A> List<ModelLoader<A, ?>> getModelLoadersForClass(@NonNull Class<A> modelClass) {
//从 cache 中取,如果没有则 build 出
List<ModelLoader<A, ?>> loaders = cache.get(modelClass);
if (loaders == null) {
loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));
cache.put(modelClass, loaders);
}
return loaders;
}
//MultiModelLoaderFactory
@NonNull
synchronized <Model> List<ModelLoader<Model, ?>> build(@NonNull Class<Model> modelClass) {
try {
List<ModelLoader<Model, ?>> loaders = new ArrayList<>();
//从 entries 遍历,通过 entry.handles(modelClass) 进行匹配
for (Entry<?, ?> entry : entries) {
if (alreadyUsedEntries.contains(entry)) {
continue;
}
if (entry.handles(modelClass)) {
alreadyUsedEntries.add(entry);
loaders.add(this.<Model, Object>build(entry));
alreadyUsedEntries.remove(entry);
}
}
return loaders;
} catch (Throwable t) {
alreadyUsedEntries.clear();
throw t;
}
}
//这里就是之前 registry 添加的参数 modelClass 和 dataClass
public boolean handles(@NonNull Class<?> modelClass, @NonNull Class<?> dataClass) {
return handles(modelClass) && this.dataClass.isAssignableFrom(dataClass);
}
public boolean handles(@NonNull Class<?> modelClass) {
return this.modelClass.isAssignableFrom(modelClass);
}
举个例子,如果用.append(Uri.class, InputStream.class, new HttpUriLoader.Factory()),那么此时的entry.factory就是HttpUriLoader.Factory.
我们接下来看一下 HttpUriLoader.Factory build
//HttpUriLoader
public class HttpUriLoader implements ModelLoader<Uri, InputStream> {
private static final Set<String> SCHEMES =
Collections.unmodifiableSet(new HashSet<>(Arrays.asList("http", "https")));
private final ModelLoader<GlideUrl, InputStream> urlLoader;
// Public API.
@SuppressWarnings("WeakerAccess")
public HttpUriLoader(ModelLoader<GlideUrl, InputStream> urlLoader) {
this.urlLoader = urlLoader;
}
@Override
public LoadData<InputStream> buildLoadData(@NonNull Uri model, int width, int height,
@NonNull Options options) {
return urlLoader.buildLoadData(new GlideUrl(model.toString()), width, height, options);
}
@Override
public boolean handles(@NonNull Uri model) {
return SCHEMES.contains(model.getScheme());
}
/**
* Factory for loading {@link InputStream}s from http/https {@link Uri}s.
*/
public static class Factory implements ModelLoaderFactory<Uri, InputStream> {
@NonNull
@Override
public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {
return new HttpUriLoader(multiFactory.build(GlideUrl.class, InputStream.class));
}
@Override
public void teardown() {
// Do nothing.
}
}
}
可以看到 HttpUriLoader 其实是又去调用了另一个解析器,这个解析器是multiFactory.build(GlideUrl.class, InputStream.class) 我们回到之前Glide 中,Registry append的地方去找一下
//Glide
.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
//HttpGlideUrlLoader
@Override
public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
@NonNull Options options) {
// GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
// spent parsing urls.
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));
}
我们回到之前 startNext 基本上所有的 startNext 里都有这段代码,以 ResourceCacheGenerator 为例
//ResourceCacheGenerator
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);
}
}
可以看到找到 modeloader后 都会调用loadData.fetcher.loadData(helper.getPriority(), this);
对应上文 HttpGlideUrlLoader
//HttpUrlFetcher
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
}
可以看到,网路获取成功后,返回 InputStream ,然后回调callback.onDataReady(result);将InputStream返回回去。同样会发现CacheGenerator都会有此方法
//ResourceCacheGenerator
@Override
public void onDataReady(Object data) {
cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.RESOURCE_DISK_CACHE,
currentKey);
}
ResourceCacheGenerator(DecodeHelper<?> helper, FetcherReadyCallback cb) {
this.helper = helper;
this.cb = cb;
}
//DecodeJob
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
我们往上找 cb 其实就是 DecodeJob,也就是最后数据会交给DecodeJob的onDataFetcherReady
//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();
}
}
}
private void decodeFromRetrievedData() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Retrieved data", startFetchTime,
"data: " + currentData
+ ", cache key: " + currentSourceKey
+ ", fetcher: " + currentFetcher);
}
Resource<R> resource = null;
try {
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
decodeFromData 通过之前的解码器进行解码获取 resource,然后进行notifyEncodeAndRelease
//DecodeJob
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
if (resource instanceof Initializable) {
((Initializable) resource).initialize();
}
Resource<R> result = resource;
LockedResource<R> lockedResource = null;
if (deferredEncodeManager.hasResourceToEncode()) {
lockedResource = LockedResource.obtain(resource);
result = lockedResource;
}
notifyComplete(result, dataSource);
stage = Stage.ENCODE;
try {
if (deferredEncodeManager.hasResourceToEncode()) {
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
// Call onEncodeComplete outside the finally block so that it's not called if the encode process
// throws.
onEncodeComplete();
}
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource);
}
DecodeJob的callback其实就是EngineJob
//EngineJob
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
this.resource = resource;
this.dataSource = dataSource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
@Override
public boolean handleMessage(Message message) {
EngineJob<?> job = (EngineJob<?>) message.obj;
switch (message.what) {
case MSG_COMPLETE:
job.handleResultOnMainThread();
break;
case MSG_EXCEPTION:
job.handleExceptionOnMainThread();
break;
case MSG_CANCELLED:
job.handleCancelledOnMainThread();
break;
default:
throw new IllegalStateException("Unrecognized message: " + message.what);
}
return true;
}
发送了MSG_COMPLETE消息
@Synthetic
void handleResultOnMainThread() {
stateVerifier.throwIfRecycled();
if (isCancelled) {
resource.recycle();
release(false /*isRemovedFromQueue*/);
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
} else if (hasResource) {
throw new IllegalStateException("Already have resource");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
// Hold on to resource for duration of request so we don't recycle it in the middle of
// notifying if it synchronously released by one of the callbacks.
engineResource.acquire();
listener.onEngineJobComplete(this, key, engineResource);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = cbs.size(); i < size; i++) {
ResourceCallback cb = cbs.get(i);
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource, dataSource);
}
}
// Our request is complete, so we can release the resource.
engineResource.release();
release(false /*isRemovedFromQueue*/);
}
我们往上找 cbs
//EngineJob
void addCallback(ResourceCallback cb) {
Util.assertMainThread();
stateVerifier.throwIfRecycled();
if (hasResource) {
cb.onResourceReady(engineResource, dataSource);
} else if (hasLoadFailed) {
cb.onLoadFailed(exception);
} else {
cbs.add(cb);
}
}
//Engine
public <R> LoadStatus load(){
...
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
...
}
//SingleRequest
public void onSizeReady(int width, int height) {
...
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);
...
}
所以其实是回调到了SingleRequest
//SingleRequest
@Override
public void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
loadStatus = null;
if (resource == null) {
GlideException exception = new GlideException("Expected to receive a Resource<R> with an "
+ "object of " + transcodeClass + " inside, but instead got null.");
onLoadFailed(exception);
return;
}
Object received = resource.get();
if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
releaseResource(resource);
GlideException exception = new GlideException("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."));
onLoadFailed(exception);
return;
}
if (!canSetResource()) {
releaseResource(resource);
status = Status.COMPLETE;
return;
}
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
private 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 {
if ((requestListener == null
|| !requestListener.onResourceReady(result, model, target, dataSource, isFirstResource))
&& (targetListener == null
|| !targetListener.onResourceReady(result, model, target, dataSource, isFirstResource))) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
最后可以看到,获取到了resource.get()获取真正的可用的数据(bitmap一类),然后通过target.onResourceReady(result, animation),回到glide的into,target其实就是BitmapImageViewTarget/DrawableImageViewTarget
//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);
}
//BitmapImageViewTarget
@Override
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
这里就设置到了图片
总结:
1. Glide.with
- 传递不同
Context,判断是否需要创建fragment,监听LifecycleListener,通过生命周期确定request调用时机,如果fragment的activity销毁了,request也停止了 registerComponentCallbacks监听onLowMemory与onTrimMemory来控制缓存- 初始化glide ,注册各类解码器
- 返回
RequestManager
2. Glide.load
- 创建
RequestBuilder,创建engine - 传入
model设置isModelSet标识位
3. Glide.into
- 创建
imageTagert - 创建
request,通过view.setTag保存,通过requestManager.track运行request。request是通过SingleRequest.obtain创建,进行必要的参数赋值 - 运行
request,首先获取图片宽高,获取成功后调用engine.load,load先从内存缓存中获取Resources。 - 如果
内存缓存内不存在Resources,创建engineJob与decodeJob,engineJob触发decodeJob
.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
-
ResourceCacheGenerator->DataCacheGenerator->SourceGenerator对应的ModelLoaders(解码器 HttpUriLoader.Factory)与DataFetcher(HttpUrlFetcher)依次处理,如果其中有磁盘缓存命中,则不会调用SourceGenerator -
loadData在数据获取成功后调用callback.onDataReady(result),然后一直往上回调,一直回调到SingleRequest的onResourceReady,最后通过target.onResourceReady设置图片
缓存机制:
-
内存缓存:
首先通过
acquired计数记录图片引用,如果被引用则放到activeResources ( 其实就是 activeEngineResources HashMap)中。当计数为0时,会触发onResourceReleased将图片存入LruResourceCache中。当使用图片的时候,又会从LruResourceCache中remove 放到activeResources中,这样设计感觉是为了提高效率。Resources存的是EngineResource,而EngineResource是各种Resource的封装,具体存储的有Bitmap(BitmapResource),byte[](BytesResource)等等 -
磁盘缓存:
glide自己写了一套
DiskLruCache,没什么特别的区别,主要还是将流存入文件中,当size超过了maxsize,就通过LinkedHashMap将最旧的移除
BitmapPool:
- put bitmap:
glide.into
--> requestManager.clear(target);
--> boolean isOwnedByUs = untrack(target);
--> requestTracker.clearRemoveAndRecycle(request)
//RequestTracker
private boolean clearRemoveAndMaybeRecycle(@Nullable Request request, boolean isSafeToRecycle) {
if (request == null) {
return true;
}
boolean isOwnedByUs = requests.remove(request);
isOwnedByUs = pendingRequests.remove(request) || isOwnedByUs;
if (isOwnedByUs) {
request.clear();
if (isSafeToRecycle) {
request.recycle();
}
}
return isOwnedByUs;
}
//SingleRequest
@Override
public synchronized void clear() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
if (status == Status.CLEARED) {
return;
}
cancel();
// Resource must be released before canNotifyStatusChanged is called.
if (resource != null) {
// 这里之后流程很多,一直调用到BitmapResource
releaseResource(resource);
}
if (canNotifyCleared()) {
target.onLoadCleared(getPlaceholderDrawable());
}
status = Status.CLEARED;
}
//BitmapResource
public void recycle() {
bitmapPool.put(bitmap); //这里就将上一次使用过的bitmap进行了缓存
}
put的流程其实是,当使用的view,本身含有request,那么就会触发清除之前的request操作,清除中会将之前使用的bitmap进行缓存放入bitmapPool中。
-
put bitmap:
最后解码会调用到 Downsampler.decode
//Downsampler downsampler.decode --> decodeFromWrappedStreams --> setInBitmap private static void setInBitmap(BitmapFactory.Options options, BitmapPool bitmapPool, int width, int height) { ... options.inBitmap = bitmapPool.getDirty(width, height, expectedConfig); ... } //LruBitmapPool @Override @NonNull public Bitmap get(int width, int height, Bitmap.Config config) { Bitmap result = getDirtyOrNull(width, height, config); if (result != null) { result.eraseColor(Color.TRANSPARENT); } else { result = createBitmap(width, height, config); } return result; } @NonNull @Override public Bitmap getDirty(int width, int height, Bitmap.Config config) { Bitmap result = getDirtyOrNull(width, height, config); if (result == null) { result = createBitmap(width, height, config); } return result; }在一般的解码的时候,使用的是
getDirty,这是返回复用的bitmap,所以里面会存在脏数据,在特殊情况下,需要进行擦除,则使用get回到
LruBitmapPool代码本身,可以看到使用的还是典型的LRU算法,只是使用的集合比较特殊。以bitmap的ByteSize为key,使用NavigableMap作为集合,能够更方便的去进行集合的扩容和删除旧bitmap的操作肯定很烂写的= = 太累了。。。 写笔记以后面试好回顾用。 至此全篇结束。