该源码解析是基于最新的Glide 4.8.0进行的
Glide基本流程分析 Glide的基本使用代码
1 Glide.with(context).load($img$).apply(RequestOptions().transform(MultiTransformation(CenterCrop(),CircleCrop())).placeholder(R.drawable.ic_default_avatar)).into(imageView);
按照上述的基本使用代码,Glide的加载过程可以分为以下几步:
Glide对象初始化
初始化代码是从Glide.get()
开始的,在其中主要做了一些事情
Glide.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @NonNull public static Glide get (@NonNull Context context) { if (glide == null ) { synchronized (Glide.class ) { if (glide == null ) { checkAndInitializeGlide(context); } } } return glide; }private static void checkAndInitializeGlide (@NonNull Context context) { if (isInitializing) { throw new IllegalStateException("You cannot call Glide.get() in registerComponents()," + " use the provided Glide instance instead" ); } isInitializing = true ; initializeGlide(context); isInitializing = false ; }
初始化Glide时再调用到initializeGlide()
去进行真正的初始化工作
Glide.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 private static void initializeGlide (@NonNull Context context) { 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; }
源码中发现GlideModule
分为两种manifestModules
和annotationGeneratedModule
,其中manifestModules
是为了兼容V3版本,以前的都是配置在AndroidManifest.xml
中,而V4版本采用注解的方式,取消了清单文件中的配置。
示例配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @GlideModule public class CustomGlideModule extends AppGlideModule { @Override public void applyOptions (Context context, GlideBuilder builder) { MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context).build(); int defaultMemoryCacheSize = calculator.getMemoryCacheSize(); int defaultBitmapPoolSize = calculator.getBitmapPoolSize(); int customMemoryCacheSize = (int ) (1.2 * defaultMemoryCacheSize); int customBitmapPoolSize = (int ) (1.2 * defaultBitmapPoolSize); builder.setMemoryCache(new LruResourceCache(customMemoryCacheSize)); builder.setBitmapPool(new LruBitmapPool(customBitmapPoolSize)); } @Override public void registerComponents (Context context, Glide glide, Registry registry) { registry.replace(GlideUrl.class , InputStream .class , new OkHttpUrlLoader .Factory (ProgressManager .getOkHttpClient ())) ; } @Override public boolean isManifestParsingEnabled () { return false ; } }
配置好GlideModule
文件后,就需要去调用其中的applyOptions()
设置Glide加载基本配置项,然后调用到了GlideBuilder.build()
去构造Glide对象,最后调用其中的regeisterComponents()
设置加载器。
接下来分析构造Glide对象的方法——GlideBuilder.build()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 @NonNull Glide build (@NonNull Context context) { if (sourceExecutor == null ) { sourceExecutor = GlideExecutor.newSourceExecutor(); } if (diskCacheExecutor == null ) { diskCacheExecutor = GlideExecutor.newDiskCacheExecutor(); } if (animationExecutor == null ) { animationExecutor = GlideExecutor.newAnimationExecutor(); } if (memorySizeCalculator == null ) { memorySizeCalculator = new MemorySizeCalculator.Builder(context).build(); } if (connectivityMonitorFactory == null ) { connectivityMonitorFactory = new DefaultConnectivityMonitorFactory(); } if (bitmapPool == null ) { int size = memorySizeCalculator.getBitmapPoolSize(); if (size > 0 ) { bitmapPool = new LruBitmapPool(size); } else { bitmapPool = new BitmapPoolAdapter(); } } if (arrayPool == null ) { arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes()); } if (memoryCache == null ) { memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize()); } if (diskCacheFactory == null ) { diskCacheFactory = new InternalCacheDiskCacheFactory(context); } if (engine == null ) { engine = new Engine( memoryCache, diskCacheFactory, diskCacheExecutor, sourceExecutor, GlideExecutor.newUnlimitedSourceExecutor(), GlideExecutor.newAnimationExecutor(), isActiveResourceRetentionAllowed); } if (defaultRequestListeners == null ) { defaultRequestListeners = Collections.emptyList(); } else { defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners); } RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory); return new Glide( context, engine, memoryCache, bitmapPool, arrayPool, requestManagerRetriever, connectivityMonitorFactory, logLevel, defaultRequestOptions.lock(), defaultTransitionOptions, defaultRequestListeners, isLoggingRequestOriginsEnabled); }
当GlideBuilder.build()
执行完毕后,最终调用到new Glide()
完成初始化。其中关键参数为Registry
后续的操作都需要用到该参数。
with()
对Glide的生命周期进行管理。
Glide对象初始化完毕后,首先会调用到的就是with()
Glide.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @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); } @NonNull public static RequestManager with (@NonNull View view) { return getRetriever(view.getContext()).get(view); }
with()
有5种重载方法,最后调用到的都是getRetriever(context).get()
RequestManagerRetriever.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 @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, 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, null , isActivityVisible(activity)); } }public RequestManager get (@NonNull View view) { if (Util.isOnBackgroundThread()) { return get(view.getContext().getApplicationContext()); } Preconditions.checkNotNull(view); Preconditions.checkNotNull(view.getContext(), "Unable to obtain a request manager for a view without a Context" ); Activity activity = findActivity(view.getContext()); if (activity == null ) { return get(view.getContext().getApplicationContext()); } if (activity instanceof FragmentActivity) { Fragment fragment = findSupportFragment(view, (FragmentActivity) activity); return fragment != null ? get(fragment) : get(activity); } android.app.Fragment fragment = findFragment(view, activity); if (fragment == null ) { return get(activity); } return get(fragment); }
简单分析上述源码可知,调用流程如下:
首先判断当前调用是否在子线程,在子线程的话,直接调用ApplicationContext
获取ReqeustManager
不在子线程即运行在主线程时,需要判断context
类型
support.Fragment或者support.FragmentActivity
:调用supportFragmentGet()
app.Activity或者app.fragment
:调用fragmentGet()
Application
:调用getApplicationManager()
view.getContext
:需要判断view的context类型,然后再走一次上面的步骤
根据流程分析,监听生命周期的方式主要是通过监听一个无UI的Fragment(位于主线程且有对应的context存在)
和监听Application(当位于后台线程或者contxt为Application)
。
其中无UI的Fragment
对应源码中的两个类RequestManagerFragment
、SupportRequestFragment
在其中构造了ActivityFragmentLifecycle
对象,在其中的关键生命周期进行联动,就可以对应的去进行加载和取消加载操作了。
RequestManagerFragment.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Override public void onStart () { super .onStart(); lifecycle.onStart(); } @Override public void onStop () { super .onStop(); lifecycle.onStop(); } @Override public void onDestroy () { super .onDestroy(); lifecycle.onDestroy(); unregisterFragmentWithRoot(); }
然后最后返回的RequestManager
对象自身也会实现LifecycleListener
接口,就可以根据对应调用跳转加载过程
RequestManager.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class RequestManager implements LifecycleListener { private final Runnable addSelfToLifecycle = new Runnable() { @Override public void run () { lifecycle.addListener(RequestManager.this ); } }; ... @Override public void onStart () { resumeRequests(); targetTracker.onStart(); } @Override public void onStop () { pauseRequests(); targetTracker.onStop(); } public void resumeRequests () { Util.assertMainThread(); requestTracker.resumeRequests(); } public void pauseRequests () { Util.assertMainThread(); requestTracker.pauseRequests(); } @Override public 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 ); } }
完成上述流程后,RequestManager就可以实现对Fragment的监听,也就等同于实现了Glide的生命周期。
{% fullimage /images/Glide的with.png,Glide的with过程,Glide的with过程%}
load()
传入需要加载的图片信息,通过with()
得到的RequestManager
进行加载。
RequestManager.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 @NonNull @CheckResult @Override public RequestBuilder<Drawable> load (@Nullable Bitmap bitmap) { return asDrawable().load(bitmap); } @NonNull @CheckResult @Override public RequestBuilder<Drawable> load (@Nullable Drawable drawable) { return asDrawable().load(drawable); } @NonNull @CheckResult @Override public RequestBuilder<Drawable> load (@Nullable String string) { return asDrawable().load(string); } @NonNull @CheckResult @Override public RequestBuilder<Drawable> load (@Nullable Uri uri) { return asDrawable().load(uri); } @NonNull @CheckResult @Override public RequestBuilder<Drawable> load (@Nullable File file) { return asDrawable().load(file); } @SuppressWarnings ("deprecation" ) @NonNull @CheckResult @Override public RequestBuilder<Drawable> load (@RawRes @DrawableRes @Nullable Integer resourceId) { return asDrawable().load(resourceId); } @SuppressWarnings ("deprecation" ) @CheckResult @Override @Deprecated public RequestBuilder<Drawable> load (@Nullable URL url) { return asDrawable().load(url); } @NonNull @CheckResult @Override public RequestBuilder<Drawable> load (@Nullable byte [] model) { return asDrawable().load(model); } @NonNull @CheckResult @Override public RequestBuilder<Drawable> load (@Nullable Object model) { return asDrawable().load(model); }
经过load()
分析,Glide加载的类型支持Bitmap
、Drawable
、String(图片地址)
、Uri
、File(图片文件)
、Integer(图片ResourceId)
、URL
、byte
,Object
。
实际内部调用到的是asDrawable.load()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public RequestBuilder<Drawable> asDrawable () { return as(Drawable.class ) ; }@NonNull @CheckResult public RequestBuilder<Bitmap> asBitmap () { return as(Bitmap.class ).apply (DECODE_TYPE_BITMAP ) ; }@NonNull @CheckResult public RequestBuilder<GifDrawable> asGif () { return as(GifDrawable.class ).apply (DECODE_TYPE_GIF ) ; }@NonNull @CheckResult public <ResourceType> RequestBuilder<ResourceType> as ( @NonNull Class<ResourceType> resourceClass) { return new RequestBuilder<>(glide, this , resourceClass, context); }
通过asDrawable()
得到RequestBuilder
对象,接下来走到ReqeustBuilder.load()
RequestBuilder.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public RequestBuilder<TranscodeType> load (@Nullable Bitmap bitmap) { return loadGeneric(bitmap) .apply(diskCacheStrategyOf(DiskCacheStrategy.NONE)); } public RequestBuilder<TranscodeType> load (@Nullable Drawable drawable) { return loadGeneric(drawable) .apply(diskCacheStrategyOf(DiskCacheStrategy.NONE)); } public RequestBuilder<TranscodeType> load (@Nullable String string) { return loadGeneric(string); } public RequestBuilder<TranscodeType> load (@Nullable Uri uri) { return loadGeneric(uri); } public RequestBuilder<TranscodeType> load (@Nullable File file) { return loadGeneric(file); } private RequestBuilder<TranscodeType> loadGeneric (@Nullable Object model) { this .model = model; isModelSet = true ; return this ; } public RequestBuilder<TranscodeType> load (@Nullable Object model) { return loadGeneric(model); }
上述的load()
都调用到了loadGeneric()
然后进行了赋值操作,确定了model
数据,然后完成了load流程。
//TODO 流程图
apply()
设置一些额外配置,例如占位图、加载错误图片、图片显示类型,圆角什么的
load()
流程结束后就得到了RequestBuilder
对象,调用其中的apply()
1 2 3 4 5 6 7 8 9 10 11 12 public class RequestBuilder <TranscodeType > extends BaseRequestOptions <RequestBuilder <TranscodeType >> implements Cloneable , ModelTypes <RequestBuilder <TranscodeType >> { ... @NonNull @CheckResult @Override public RequestBuilder<TranscodeType> apply (@NonNull BaseRequestOptions<?> requestOptions) { Preconditions.checkNotNull(requestOptions); return super .apply(requestOptions); } ... }
调用到了super.apply()
其实就是BaseRequestOptions.apply()
BaseRequestOptions.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @NonNull @CheckResult public T apply (@NonNull BaseRequestOptions<?> o) { if (isAutoCloneEnabled) { return clone().apply(o); } BaseRequestOptions<?> other = o; if (isSet(other.fields, SIZE_MULTIPLIER)) { sizeMultiplier = other.sizeMultiplier; } ... fields |= other.fields; options.putAll(other.options); return selfOrThrowIfLocked(); }
isSet()
是判断该属性是否设置,若已设置过则替换,设置完毕后,得到一个RequestBuilder
对象,不过已经设置了RequestOptions
里面包含了一些显示上以及缓存上的配置。
into()
——最关键步骤
进行图片的加载与显示
创建请求Request
起点是从RequestBuilder.into()
开始
RequestBuilder.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 @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 ) { 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( glideContext.buildImageViewTarget(view, transcodeClass), null , requestOptions, Executors.mainThreadExecutor()); }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 (!Preconditions.checkNotNull(previous).isRunning()) { previous.begin(); } return target; } requestManager.clear(target); target.setRequest(request); requestManager.track(target, request); return target; }
通过buildRequest()
构建图片加载请求对象。
RequestBuilder.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 private Request buildRequest ( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> requestOptions, Executor callbackExecutor) { return buildRequestRecursive( target, targetListener, null , transitionOptions, requestOptions.getPriority(), requestOptions.getOverrideWidth(), requestOptions.getOverrideHeight(), requestOptions, callbackExecutor); } private Request buildRequestRecursive (...) { ErrorRequestCoordinator errorRequestCoordinator = null ; if (errorBuilder != null ) { errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator); parentCoordinator = errorRequestCoordinator; } Request mainRequest = buildThumbnailRequestRecursive(...); if (errorRequestCoordinator == null ) { return mainRequest; } Request errorRequest = errorBuilder.buildRequestRecursive(...); errorRequestCoordinator.setRequests(mainRequest, errorRequest); return errorRequestCoordinator; ... }private Request buildThumbnailRequestRecursive (...) { if (thumbnailBuilder != null ) { if (isThumbnailBuilt) { throw new IllegalStateException("You cannot use a request as both the main request and a " + "thumbnail, consider using clone() on the request(s) passed to thumbnail()" ); } TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions = thumbnailBuilder.transitionOptions; 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); ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator); Request fullRequest = obtainRequest(...); isThumbnailBuilt = true ; Request thumbRequest = thumbnailBuilder.buildRequestRecursive(...); isThumbnailBuilt = false ; coordinator.setRequests(fullRequest, thumbRequest); return coordinator; } else if (thumbSizeMultiplier != null ) { ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator); Request fullRequest = obtainRequest(...); BaseRequestOptions<?> thumbnailOptions = requestOptions.clone().sizeMultiplier(thumbSizeMultiplier); Request thumbnailRequest = obtainRequest(...); coordinator.setRequests(fullRequest, thumbnailRequest); return coordinator; } else { return obtainRequest(...); } } 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(...); }
总结一下创建请求的流程,最后调用的是SingleRequest
对象。
通过RequestBuilder.buildRequest()
创建Request
对象,调用到buildRequestRecursive()
执行创建逻辑
先判断设置过RequestBuilder.error()
参数,如果设置过errorRequest
,需要通过errorRequest
和mainRequest
得到ErrorRequestCoordinator(实现Request接口)
对象。
没设置过RequestBuilder.error()
参数,则向下判断是否设置过ReqeustBuilder.thumbnail()
参数,设置ReqeustBuilder.thumbnail()
有两种方法:
ReqeustBuilder.thumbnail(RequestBuilder thumbnailBuilder)
:自定义要显示的缩略图
ReqeustBuilder.thumbnail(float thumbSizeMultiper)
:设置原图缩放比例
只要设置了其中的一种,就会产生thumbRequest
对象,然后与fullRequest
得到ThumbnailRequestCoordinator(实现Request接口)
对象。
ReqeustBuilder.thumbnail()
也未设置,则最终调用SingleRequest.obtain()
得到SingleRequest(实现Request接口)
对象。
errorRequest
表示了加载错误的请求
thumbRequest
表示了缩略图加载请求
mainRequest
和fullRequest
都代表了原始图片加载请求。
上述创建请求流程执行完毕后,就是发送请求。
发送请求
发送请求通过调用Request
实现。
在创建请求 中,创建完成后会调用到requestManager.track(target, request);
去发送请求
RequestManager.java 1 2 3 4 5 6 synchronized void track (@NonNull Target<?> target, @NonNull Request request) { targetTracker.track(target); requestTracker.runRequest(request); }
RequestTracker.java 1 2 3 4 5 6 7 8 9 10 11 12 13 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.begin()
,Request
是一个接口,singleRequest
是具体的实现类,即调用到SingleRequest.begin()
SingleRequest.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 @Override public synchronized void begin () { 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" ); } if (status == Status.COMPLETE) { onResourceReady(resource, DataSource.MEMORY_CACHE); return ; } 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)); } }@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; 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(...); if (status != Status.RUNNING) { loadStatus = null ; } if (IS_VERBOSE_LOGGABLE) { logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime)); } }
上述流程主要是去计算得到 被加载图片的尺寸信息,如果手动设置了尺寸通过override
那么通过合法性校验后,加载的图片大小就会为用户设置尺寸,否则使用Target
的尺寸信息。
Target
是一个接口,主要意义是提供View的确切尺寸信息以及对回调结果进行处理。
{% fullimage /images/Glide发送请求.png,Glide发送请求,Glide发送请求%}
加载图片 接下来调用Engine.load()
开始加载图片,包括三级缓存的部分。
Engine.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 public synchronized <R> LoadStatus load (...) { long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0 ; EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options); 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 ; } 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 ; } 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<R> engineJob = engineJobFactory.build( key, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache); DecodeJob<R> decodeJob = decodeJobFactory.build(...); jobs.put(key, engineJob); engineJob.addCallback(cb, callbackExecutor); engineJob.start(decodeJob); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Started new load" , startTime, key); } return new LoadStatus(cb, engineJob); }
在Engine.load()
,主要执行逻辑是:先从一级内存缓存-弱引用
中查找指定资源,找不到则去二级内存缓存-LRUCache
中去查找,再没有就转到DecodeJob
去加载图片。
加载图片的具体实现细节会单独在Glide缓存实现原理 说明。
显示图片 当图片从三级缓存中取出后,最终得到的是一个Resource
对象,然后再回调到SingleRequest.onResourceReady()
中
SingleRequest.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 @Override public synchronized void onResourceReady (Resource<?> resource, DataSource dataSource) { stateVerifier.throwIfRecycled(); loadStatus = null ; if (resource == null ) { onLoadFailed(exception); return ; } Object received = resource.get(); if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) { releaseResource(resource); onLoadFailed(exception); return ; } if (!canSetResource()) { releaseResource(resource); status = Status.COMPLETE; return ; } onResourceReady((Resource<R>) resource, (R) received, dataSource); }private synchronized void onResourceReady (Resource<R> resource, R result, DataSource dataSource) { 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(); }
在SingleRequest.onSourceReady()
主要回调了Target.onResourceReady()
,把Resource
显示到Target
上,实质就是into()
传入的Target对象。
ImageViewTarget.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @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); }protected abstract void setResource (@Nullable Z resource) ;
其中有两个类继承了ImageViewTarget
用于实现不同的功能。分别是DrawableImageViewTarget
、BitmapImageViewTarget
。
DrawableImageViewTarget.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class DrawableImageViewTarget extends ImageViewTarget <Drawable > { public DrawableImageViewTarget (ImageView view) { super (view); } @SuppressWarnings ({"unused" , "deprecation" }) @Deprecated public DrawableImageViewTarget (ImageView view, boolean waitForLayout) { super (view, waitForLayout); } @Override protected void setResource (@Nullable Drawable resource) { view.setImageDrawable(resource); } }
最终通过ImageView.setImageDrawable()
将图片显示在ImageView上。
{% fullimage /images/Glide显示图片.png,Glide显示图片,Glide显示图片%}
Glide缓存实现原理
Glide的缓存主要分成了两个模块,一个是内存缓存 ,另一部分是硬盘缓存 。
内存缓存 :防止应用重复将图片数据读取到内存当中
硬盘缓存 :防止应用重复从网络或其他地方重复下载和读取数据
缓存配置 1.在自定义的GlideModule
中的applyOptions()
中设置具体的缓存参数
1 2 3 4 5 6 7 8 9 10 11 12 13 @GlideModule public class CustomGlideModule extends AppGlideModule { @Override public void applyOptions (Context context, GlideBuilder builder) { MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context).build(); int defaultMemoryCacheSize = calculator.getMemoryCacheSize(); int defaultBitmapPoolSize = calculator.getBitmapPoolSize(); int customMemoryCacheSize = (int ) (1.2 * defaultMemoryCacheSize); int customBitmapPoolSize = (int ) (1.2 * defaultBitmapPoolSize); builder.setMemoryCache(new LruResourceCache(customMemoryCacheSize)); builder.setBitmapPool(new LruBitmapPool(customBitmapPoolSize)); } }
2.在具体请求中设置缓存参数
1 2 val requestBuilder =Glide.with(this ).asBitmap().apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true )).load(path)
缓存Key 缓存功能,就需要有对应的缓存Key,应用可以根据这个Key找到对应的缓存文件。Glide的缓存Key生成代码如下
Engine.java 1 2 3 4 public synchronized <R> LoadStatus load (...){ EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,resourceClass, transcodeClass, options) ; ... }
model
对应的就是load()
过程中传入的参数,例如传入String(图片加载地址)
,那么对应的就是加载地址。决定生成Key的参数有很多。
如果设置了override
修改了加载尺寸,那也会有不同的key生成。
内存缓存 默认情况下,内存缓存是自动开启的,加载图片完成后,就会默认在内存中缓存,然后下次再调用时就会从内存中直接读取显示,无需重新加载。
可以通过设置skipMemoryCache(true)
来关闭内存缓存功能。
Glide中的内存缓存主要分为两部分处理:弱引用复用机制 和LRUCache 。
弱引用复用 —— ActiveResources
从正在活动的资源中取出缓存进行复用
Engine.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public synchronized <R> LoadStatus load (...) { ... 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 ; } ... } @Nullable private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) { if (!isMemoryCacheable) { return null ; } EngineResource<?> active = activeResources.get(key); if (active != null ) { active.acquire(); } return active; }
对应的Resource文件要从ActiveResource
中获取
ActiveResource.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>(); synchronized void deactivate (Key key) { ResourceWeakReference removed = activeEngineResources.remove(key); if (removed != null ) { removed.reset(); } }@Nullable synchronized EngineResource<?> get(Key key) { ResourceWeakReference activeRef = activeEngineResources.get(key); if (activeRef == null ) { return null ; } EngineResource<?> active = activeRef.get(); if (active == null ) { cleanupActiveReference(activeRef); } return active; } void cleanupActiveReference (@NonNull ResourceWeakReference ref) { synchronized (listener) { synchronized (this ) { activeEngineResources.remove(ref.key); if (!ref.isCacheable || ref.resource == null ) { return ; } EngineResource<?> newResource = new EngineResource<>(ref.resource, true , false ); newResource.setResourceListener(ref.key, listener); listener.onResourceReleased(ref.key, newResource); } } } @VisibleForTesting static final class ResourceWeakReference extends WeakReference <EngineResource <?>> { @SuppressWarnings ("WeakerAccess" ) @Synthetic final Key key; @SuppressWarnings ("WeakerAccess" ) @Synthetic final boolean isCacheable; @Nullable @SuppressWarnings ("WeakerAccess" ) @Synthetic Resource<?> resource; @Synthetic @SuppressWarnings ("WeakerAccess" ) ResourceWeakReference( @NonNull Key key, @NonNull EngineResource<?> referent, @NonNull ReferenceQueue<? super EngineResource<?>> queue, boolean isActiveResourceRetentionAllowed) { super (referent, queue); this .key = Preconditions.checkNotNull(key); this .resource = referent.isCacheable() && isActiveResourceRetentionAllowed ? Preconditions.checkNotNull(referent.getResource()) : null ; isCacheable = referent.isCacheable(); } void reset () { resource = null ; clear(); } }
listener
对应的就是Engine
对象,调用到Engine.onResourceReleased()
Engine.java 1 2 3 4 5 6 7 8 9 10 11 @Override public synchronized void onResourceReleased (Key cacheKey, EngineResource<?> resource) { activeResources.deactivate(cacheKey); if (resource.isCacheable()) { cache.put(cacheKey, resource); } else { resourceRecycler.recycle(resource); } }
ActivieResources
采用HashMap + WeakReference
来保存EngineResource
,不会有上限。然后get()
从activeEngineResources
弱引用HashMap中获取数据,这里分为两种情况:
获取到弱引用关联对象EngineResource
,则直接返回结果
获取不到关联对象,则需进行清除工作调用cleanupActiveResource()
,在activeEngineResources
移除对应的key和引用,在判断是否开启缓存,若开启则缓存至LRUCache
中。
总结:
ActiveResources
采用弱引用的方式,里面存储的是EngineResource
,同时采用强引用保存EngineResource.resource
,在ActiveResources
中还会有一个清理线程在运行,负责当EngineResource
被回收时,就去取出对应的EngineResource.resource
,然后创建一个新的EngineResource
对象,回调到Engine.onResourceReleased()
中,在其中做内存缓存,之后调用ActivityResources.deactivate()
移除对应的强引用。
{% fullimage /images/内存缓存-弱引用机制.png,内存缓存-弱引用机制,内存缓存-弱引用机制%}
LRUCache
在当前活动资源中没有对应的缓存时,就要从内存中去进行读取
Engine.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public synchronized <R> LoadStatus load (...) { ... 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 ; } } private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) { if (!isMemoryCacheable) { return null ; } EngineResource<?> cached = getEngineResourceFromCache(key);① if (cached != null ) { cached.acquire(); activeResources.activate(key, cached);② } return cached; } private EngineResource<?> getEngineResourceFromCache(Key key) { Resource<?> cached = cache.remove(key);③ final EngineResource<?> result; if (cached == null ) { result = null ; } else if (cached instanceof EngineResource) { result = (EngineResource<?>) cached; } else { result = new EngineResource<>(cached, true , true ); } return result; }
loadFromCache()
实际调用到getEngineResourceFromCache()
获取内存缓存中的资源,如果找到,缓存数量+1,然后会把cached
放入ActiveResources
中,变为活动资源,对应的要在内存缓存
中移除引用。
①getEngineResourceFromCache(key)
:从内存缓存中根据缓存key获取缓存
②activeResources.activate(key, cached)
:取出的缓存数据存入到活动资源中
ActiveResources.java 1 2 3 4 5 6 7 8 9 10 11 12 synchronized void activate (Key key, EngineResource<?> resource) { ResourceWeakReference toPut = new ResourceWeakReference( key, resource, resourceReferenceQueue, isActiveResourceRetentionAllowed); ResourceWeakReference removed = activeEngineResources.put(key, toPut); if (removed != null ) { removed.reset(); } }
③cache.remove(key)
:从内存缓存中移除对应缓存
cache
对应的是MemoryCache
是一个接口,实现类为LruResourceCache
LruResourceCache.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class LruResourceCache extends LruCache <Key , Resource <?>> implements MemoryCache { private ResourceRemovedListener listener; public LruResourceCache (long size) { super (size); } @Override public void setResourceRemovedListener (@NonNull ResourceRemovedListener listener) { this .listener = listener; } @Override protected void onItemEvicted (@NonNull Key key, @Nullable Resource<?> item) { if (listener != null && item != null ) { listener.onResourceRemoved(item); } } @Override protected int getSize (@Nullable Resource<?> item) { if (item == null ) { return super .getSize(null ); } else { return item.getSize(); } } @SuppressLint ("InlinedApi" ) @Override public void trimMemory (int level) { if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { clearMemory(); } else if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN || level == android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) { trimToSize(getMaxSize() / 2 ); } } }
LruResourceCache
继承自LruCache
,不过内部计算缓存大小是通过Resource
对象的大小累计,还增加了资源移除监听,为了和ActiveResources
进行联动。
LruResourceCache
的size
是在自定义GlideModule
中的 applyOptions()
时设置进来的,如果未设置会采用MemorySizeCalculator.getMemoryCacheSize()
设置。
当前在内存中缓存的对象都是Resource
,而不是通常认为的Bitmap,下面会介绍到转码的过程。
小结 在内存缓存
中,分为两种方案:从弱引用中获取 、从内存缓存中获取 。两者的关系简单概括就是:
读取内存缓存时,会优先从ActiveResources
中读取,读取到的话,需要判断当前包装Resource
的弱引用对象是否被回收,未回收则直接返回。被回收的话,需要重新包装EngineResource.resource
然后存入到内存缓存中并需要移除ActiveResources
对其的引用。
从ActiveResources
中没有获取到对应缓存时,就从LruResourceCache
中去获取,获取到的话,就需要从当前内存缓存中移除对应缓存引用,并存入到ActiveResources
中。
实现了正在使用的图片通过弱引用进行缓存,未使用的图片通过LruCache进行缓存。
ActiveResources
优先级高于LruResourceCache
。
比较两者之间的区别:
弱引用获取
内存缓存获取
基础实现
HashMap
LinkedHashMap(LruCache )
可否禁用
用户无法禁用
通过skipMemoryCache(true)
禁用
运行位置
内存
内存
释放时机
依赖垃圾回收机制弱引用实现,GC时被回收
采用最近最少使用 来淘汰数据
磁盘缓存
当内存中不存在缓存时,就会向下从硬盘中去读取缓存数据
通过设置diskCacheStrategy(DiskCacheStrategy.NONE)
来关闭硬盘缓存功能。
Engine.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public synchronized <R> LoadStatus load (...) { ... 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<R> engineJob = engineJobFactory.build(...); DecodeJob<R> decodeJob = decodeJobFactory.build(... , engineJob); jobs.put(key, engineJob); engineJob.addCallback(cb, callbackExecutor); engineJob.start(decodeJob); }
从内存中读取不到缓存时,Engine
尝试从jobs
读取对应的EngineJob
缓存,如存在就去回调加载成功或加载失败
。不存在的话,就需要新建一个EngineJob
以及DecodeJob
去加载图片。
EngineJob.java 1 2 3 4 5 6 7 public synchronized void start (DecodeJob<R> decodeJob) { this .decodeJob = decodeJob; GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); executor.execute(decodeJob); }
通过线程池去执行decodeJob
,DecodeJob
实现了Runnable
接口,execute()
直接调用到run()
DecodeJob.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 @SuppressWarnings ("PMD.AvoidRethrowingException" ) @Override public void run () { GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)" , model); DataFetcher<?> localFetcher = currentFetcher; try { if (isCancelled) { notifyFailed(); return ; } runWrapped(); } catch (CallbackException e) { throw e; } catch (Throwable t) { 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 enum RunReason { INITIALIZE, SWITCH_TO_SOURCE_SERVICE, DECODE_DATA, }
调用DecodeJob.run()
开始加载资源,内部调用runWrapped()
,此时runWrapped()
中会根据runReason
执行不同的操作,runReason
就是用于控制当前执行到的任务。
INITIALIZE
:第一次调用run()
,执行目的是从diskcache
中获取缓存
SWITCH_TO_SOURCE_SERVICE
:从diskcache
中获取缓存失败,需要从数据源获取
DECODE_DATA
:缓存数据成功,对数据进行解析
获取硬盘缓存数据 DecodeJob.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 private DiskCacheStrategy diskCacheStrategy;private void runGenerators () { currentThread = Thread.currentThread(); startFetchTime = LogTime.getLogTime(); boolean isStarted = false ; while (!isCancelled && currentGenerator != null && !(isStarted = currentGenerator.startNext())) { 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) { 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 onlyRetrieveFromCache ? Stage.FINISHED : 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); } } private enum Stage { INITIALIZE, RESOURCE_CACHE, DATA_CACHE, SOURCE, ENCODE, FINISHED, }
stage
对应Stage
枚举类,可以通过DiskCacheStrategy
得到Stage
。
DiskCacheStrategy
参数解释:
NONE
:表示不缓存任何内容
DATA
:只缓存原始图片
RESOURCE
:只缓存转换后的图片
ALL
:原始图片和转换后的图片都进行缓存
AUTOMATIC
:尝试选择最佳策略。针对加载数据类型进行区分:
加载本地图片:缓存原始图片
加载网络图片:缓存转换后的图片
stage
默认尽量就是INITIALIZE
,通过递归调用getNextStage()
向下推进,并改变stage
表示进行状态。stage
的推进过程也表示了硬盘缓存的查找顺序。
Stage
描述
INITIALIZE
初始状态
RESOURCE_CACHE
转换后缓存 调用ResourceCacheGenerator
DATA_CACHE
原图缓存 调用DataCacheGenerator
SOURCE
远程获取图片 调用SourceGenerator
ENCODE
解析资源,生成Resource
对象
FINISHED
解析完成
查找缓存从初始查找开始
->查找转换后图片缓存
->查找原图图片缓存
->前面都没找到就去进行远程加载
->加载完成后就开始解析数据
->解析完成
。
查找缓存从currentGenerator.startNext()
开始,就先从ResourceCacheGenerator
开始
ResourceCacheGenerator.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 private File cacheFile;public boolean startNext () { List<Key> sourceIds = helper.getCacheKeys(); if (sourceIds.isEmpty()) { return false ; } List<Class<?>> resourceClasses = helper.getRegisteredResourceClasses(); if (resourceClasses.isEmpty()) { if (File.class .equals (helper .getTranscodeClass ())) { return false ; } throw new IllegalStateException( "Failed to find any load path from " + helper.getModelClass() + " to " + helper.getTranscodeClass()); } while (modelLoaders == null || !hasNextModelLoader()) { resourceClassIndex++; if (resourceClassIndex >= resourceClasses.size()) { sourceIdIndex++; if (sourceIdIndex >= sourceIds.size()) { return false ; } resourceClassIndex = 0 ; } Key sourceId = sourceIds.get(sourceIdIndex); Class<?> resourceClass = resourceClasses.get(resourceClassIndex); Transformation<?> transformation = helper.getTransformation(resourceClass); currentKey = new ResourceCacheKey( helper.getArrayPool(), sourceId, helper.getSignature(), helper.getWidth(), helper.getHeight(), transformation, resourceClass, helper.getOptions()); cacheFile = helper.getDiskCache().get(currentKey); if (cacheFile != null ) { 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; }
根据相关参数生成对应的cacheKey
,然后从DiskCache
中取出对应的cacheFile
,然后使用FileLoader
解析该文件。
helper.getDiskCache()
对应的就是DiskLruCacheWrapper
类,内部包装了DiskLruCache
,内部实现了整套的文件读写功能。
远程获取数据 若为初次加载的数据,肯定不会在diskCache
中获取到,就需要远程加载。
SourceGenerator.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 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 ; while (!started && hasNextModelLoader()) { loadData = helper.getLoadData().get(loadDataListIndex++); if (loadData != null && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource()) || helper.hasLoadPath(loadData.fetcher.getDataClass()))) { started = true ; loadData.fetcher.loadData(helper.getPriority(), this ); } } return started; }private void cacheData (Object dataToCache) { long startTime = LogTime.getLogTime(); try { Encoder<Object> encoder = helper.getSourceEncoder(dataToCache); DataCacheWriter<Object> writer = new DataCacheWriter<>(encoder, dataToCache, helper.getOptions()); originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature()); helper.getDiskCache().put(originalKey, writer); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Finished encoding source to cache" + ", key: " + originalKey + ", data: " + dataToCache + ", encoder: " + encoder + ", duration: " + LogTime.getElapsedMillis(startTime)); } } finally { loadData.fetcher.cleanup(); } sourceCacheGenerator = new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this ); } @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); } }
在SourceGenerator.startNext()
会优先判断数据是否在DiskCache
中,若存在调用cacheData()
创建DataCacheGenerator
调用其startNext()
。不存在则循环去获取loadData
,通过DecodeHelper.getLoadData()
,然后继续执行loadData.fetch.loadData()
去加载数据,加载成功后回调到onDataReady()
。
现在开始按步骤分析:
加载远程数据——地址加载(HttpUrlFetcher
) HttpUrlFetcher.java 1 2 3 4 5 6 7 8 9 public void loadData (Priority priority, DataCallback<? super InputStream> callback) { try { InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0 , null , glideUrl.getHeaders()); callback.onDataReady(result); } catch (IOException e) { callback.onLoadFailed(e); } finally { } }
加载本地数据——本地文件加载(ByteBufferFetcher
) ByteBufferFileLoader.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private static final class ByteBufferFetcher implements DataFetcher <ByteBuffer > { ... @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); } }
loadData()
成功后,回调到SourceGenerator.onDataReady()
中。这时需要判断是否开启了硬盘缓存,如果关闭了直接回调到DecodeJob.onDataFetcherReady()
,开启了的话,就继续调用到DecodeJob.reschedule()
。
DecodeJob.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 @Override public void reschedule() { runReason = RunReason.SWITCH_TO_SOURCE_SERVICE; callback.reschedule(this); } @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; //再次调用到 runWrapped() 此时会走向 decodeFromRetrievedData() callback.reschedule(this); } else { GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData"); try { // 解析数据的真正逻辑 decodeFromRetrievedData(); } finally { 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); } }
在reschedule()
,把runReason
设为SWITCH_TO_SOURCE_SERVICE
,继续调用到EngineJob.reschedule()
,再次执行到DecodeJob.run()
不过已经在一个新的线程池中继续执行。
在onDataFetcherReady()
中,会判断当前线程是否相同,不同的话,设置runReason
为DECODE_DATA
,重新执行EngineJob.reschedule()
还会走到run()
中,继续执行到decodeFromRetrievedData()
,线程相同则直接执行。
解析数据
此时拿到的数据类型还是InputStream
或者ByteBuffer
,需要解析成常用的File
或者Bitmap
。
此时runReason
为DECODE_DATA
,调用到decodeFromRetrievedData()
DecodeJob.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 private Object currentData; private void decodeFromRetrievedData () { ... 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(); } } private <Data> Resource<R> decodeFromData (DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlideException { try { ... Resource<R> result = decodeFromFetcher(data, dataSource); return result; } finally { fetcher.cleanup(); } } @SuppressWarnings ("unchecked" ) private <Data> Resource<R> decodeFromFetcher (Data data, DataSource dataSource) throws GlideException { LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass()); return runLoadPath(data, dataSource, path); } private <Data, ResourceType> Resource<R> runLoadPath (Data data, DataSource dataSource, LoadPath<Data, ResourceType, R> path) throws GlideException { Options options = getOptionsWithHardwareConfig(dataSource); DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data); try { return path.load( rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource)); } finally { rewinder.cleanup(); } }
调用decodeFromRetrievedData
开始解析加载返回的数据,数据格式可能为InputSteam
、ByteBuffer
。向下调用到decodeFromData()
,再到decodeFromFetcher()
,最终通过DecodeHelper.getLoadPath()
得到的LoadPath
去对获取的数据进行解析。
LoadPath.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public Resource<Transcode> load (DataRewinder<Data> rewinder, @NonNull Options options, int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException { List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire()); try { return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables); } finally { listPool.release(throwables); } }private Resource<Transcode> loadWithExceptionList (DataRewinder<Data> rewinder, @NonNull Options options, int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback, List<Throwable> exceptions) throws GlideException { Resource<Transcode> result = null ; for (int i = 0 , size = decodePaths.size(); i < size; i++) { DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i); try { result = path.decode(rewinder, width, height, options, decodeCallback); } catch (GlideException e) { exceptions.add(e); } if (result != null ) { break ; } } if (result == null ) { throw new GlideException(failureMessage, new ArrayList<>(exceptions)); } return result; }
DecodePath.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public Resource<Transcode> decode (DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException { Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options); Resource<ResourceType> transformed = callback.onResourceDecoded(decoded); return transcoder.transcode(transformed, options); } @NonNull private Resource<ResourceType> decodeResource (DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options) throws GlideException { List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire()); try { return decodeResourceWithList(rewinder, width, height, options, exceptions); } finally { listPool.release(exceptions); } }@NonNull private Resource<ResourceType> decodeResourceWithList (DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, List<Throwable> exceptions) throws GlideException { Resource<ResourceType> result = null ; for (int i = 0 , size = decoders.size(); i < size; i++) { ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i); try { DataType data = rewinder.rewindAndGet(); if (decoder.handles(data, options)) { data = rewinder.rewindAndGet(); result = decoder.decode(data, width, height, options); } } catch (IOException | RuntimeException | OutOfMemoryError e) { } if (result != null ) { break ; } } if (result == null ) { throw new GlideException(failureMessage, new ArrayList<>(exceptions)); } return result; }
LoadPath.load()
通过调用loadWithExceptionList()
,循环获取DecodePath
对象,然后调用其自身的decode()
进行数据解析。DecodePath
与LoadPath
逻辑相似,最终在DecodePath.decodeResourceWithList()
中循环获取ResourceDecoder
对象,通过DateRewinder.rewindAndGet()
获取要解析数据的格式(比如ByteBuffer,InputStream
),然后调用decoder.decode
继续解析数据。
获取数据格式 由上述流程可知,我们能获得的数据类型为InputStream
和ByteBuffer
,对应的就会有两种DataRewinder
InputStreamRewinder.java 1 2 3 4 5 6 7 private final RecyclableBufferedInputStream bufferedStream;@NonNull @Override public InputStream rewindAndGet () throws IOException { bufferedStream.reset(); return bufferedStream; }
ByteBufferRewinder.java 1 2 3 4 5 6 @NonNull @Override public ByteBuffer rewindAndGet () { buffer.position(0 ); return buffer; }
将传进来的data可以转换成对应的数据格式。
根据格式转换相应类型 得到对应数据格式后,就需要通过ResourceDecoder.decode()
去解析数据。
ResourceDecoder.java 1 2 3 4 5 6 7 8 9 public interface ResourceDecoder <T , Z > { boolean handles (@NonNull T source, @NonNull Options options) throws IOException ; */ @Nullable Resource<Z> decode (@NonNull T source, int width, int height, @NonNull Options options) throws IOException ; }
T
代表需要被解析的类型(例如InputStream、ByteBuffer),Z
代表解析的结果类型(例如Bitmap、Drawable)。
ResourceDecoder
在原码中有很多实现类,StreamBitmapDecoder
、ButeBufferBitmapDecoder
,此处拿出常用的StreamBitmapDecoder
进行分析。
StreamBitmapDecoder.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Override public boolean handles (@NonNull InputStream source, @NonNull Options options) { return downsampler.handles(source); }@Override public Resource<Bitmap> decode (@NonNull InputStream source, int width, int height, @NonNull Options options) throws IOException { final RecyclableBufferedInputStream bufferedStream; final boolean ownsBufferedStream; if (source instanceof RecyclableBufferedInputStream) { bufferedStream = (RecyclableBufferedInputStream) source; ownsBufferedStream = false ; } else { bufferedStream = new RecyclableBufferedInputStream(source, byteArrayPool); ownsBufferedStream = true ; } ExceptionCatchingInputStream exceptionStream = ExceptionCatchingInputStream.obtain(bufferedStream); MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream); UntrustedCallbacks callbacks = new UntrustedCallbacks(bufferedStream, exceptionStream); try { return downsampler.decode(invalidatingStream, width, height, options, callbacks); } finally { exceptionStream.release(); if (ownsBufferedStream) { bufferedStream.release(); } } }
ResourceDecode.decode()
内部是通过Downsampler.decode()
进行解析
Downsampler.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 @SuppressWarnings ({"resource" , "deprecation" }) public Resource<Bitmap> decode (InputStream is, int requestedWidth, int requestedHeight, Options options, DecodeCallbacks callbacks) throws IOException { ... try { Bitmap result = decodeFromWrappedStreams(is, bitmapFactoryOptions, downsampleStrategy, decodeFormat, isHardwareConfigAllowed, requestedWidth, requestedHeight, fixBitmapToRequestedDimensions, callbacks); return BitmapResource.obtain(result, bitmapPool); } finally { releaseOptions(bitmapFactoryOptions); byteArrayPool.put(bytesForOptions); } }private Bitmap decodeFromWrappedStreams (InputStream is, BitmapFactory.Options options, DownsampleStrategy downsampleStrategy, DecodeFormat decodeFormat, boolean isHardwareConfigAllowed, int requestedWidth, int requestedHeight, boolean fixBitmapToRequestedDimensions, DecodeCallbacks callbacks) throws IOException { Bitmap downsampled = decodeStream(is, options, callbacks, bitmapPool); callbacks.onDecodeComplete(bitmapPool, downsampled); }private static Bitmap decodeStream (InputStream is, BitmapFactory.Options options, DecodeCallbacks callbacks, BitmapPool bitmapPool) throws IOException { ... TransformationUtils.getBitmapDrawableLock().lock(); try { result = BitmapFactory.decodeStream(is, null , options); } catch (IllegalArgumentException e) { ... throw bitmapAssertionException; } finally { TransformationUtils.getBitmapDrawableLock().unlock(); } ... }
Downsampler.decode()
内部主要实现依靠decodeFromWrapperStreams()
,内部主要是配置BitmapFactory.Options
。去控制图片的缩放(scale)、旋转(rotate)、复用(inBitmap)等方面配置。最后通过decodeStream
解析输入流,最后生成Bitmap对象返回。
获取图片后继续处理(例如圆角) DecodePath.java 1 2 3 4 5 6 7 8 public Resource<Transcode> decode (DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException { Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options); Resource<ResourceType> transformed = callback.onResourceDecoded(decoded); return transcoder.transcode(transformed, options); }
decodeResource
最终会调到DecodeJob.onResourceDecoded()
进行Transform
处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 <Z> Resource<Z> onResourceDecoded (DataSource dataSource, @NonNull Resource<Z> decoded) { @SuppressWarnings ("unchecked" ) Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass(); Transformation<Z> appliedTransformation = null ; Resource<Z> transformed = decoded; if (dataSource != DataSource.RESOURCE_DISK_CACHE) { appliedTransformation = decodeHelper.getTransformation(resourceSubClass); transformed = appliedTransformation.transform(glideContext, decoded, width, height); } if (!decoded.equals(transformed)) { decoded.recycle(); }if (diskCacheStrategy.isResourceCacheable(isFromAlternateCacheKey, dataSource, encodeStrategy)) { if (encoder == null ) { throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass()); } final Key key; switch (encodeStrategy) { case SOURCE: key = new DataCacheKey(currentSourceKey, signature); break ; case TRANSFORMED: key = new ResourceCacheKey( decodeHelper.getArrayPool(), currentSourceKey, signature, width, height, appliedTransformation, resourceSubClass, options); break ; default : throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy); } ... } return result; }
从这里可看出 保存原图和保存转换后图片的缓存key是不一致的。
缓存原图用的是DataCacheKey
,保存转换后图片用的是ResourceCacheKey
上述数据处理完毕后,层层回溯到达了decodeFromRetrievedData
()
DecodeJob.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 private void decodeFromRetrievedData () { ... 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(); } } private void notifyEncodeAndRelease (Resource<R> resource, DataSource dataSource) { if (resource instanceof Initializable) { ((Initializable) resource).initialize(); } notifyComplete(result, dataSource); stage = Stage.ENCODE; ... } private void notifyComplete (Resource<R> resource, DataSource dataSource) { setNotifiedOrThrow(); callback.onResourceReady(resource, dataSource); }
经过解析数据那一套流程下来后,数据已经加载完成,然后回到DecodeJob.decodeFromRetrieveData()
,这时Resource对象不为空,向下继续调用notifyEncodeAndRelease()
,内部调用到notifyComplete()
再回调到EngineJob.onResourceReady()
。
EngineJob.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Override public void onResourceReady (Resource<R> resource, DataSource dataSource) { synchronized (this ) { this .resource = resource; this .dataSource = dataSource; } notifyCallbacksOfResult(); }void notifyCallbacksOfResult () { ResourceCallbacksAndExecutors copy; Key localKey; EngineResource<?> localResource; listener.onEngineJobComplete(this , localKey, localResource); for (final ResourceCallbackAndExecutor entry : copy) { entry.executor.execute(new CallResourceReady(entry.cb)); } decrementPendingCallbacks(); }
EngineJob.onResourceReady()
资源加载完成后,通过notifyCallbacksOfResulr()
调用到Engine.onEngineJobComplete()
Engine.java 1 2 3 4 5 6 7 8 9 10 11 12 13 public synchronized void onEngineJobComplete ( EngineJob<?> engineJob, Key key, EngineResource<?> resource) { if (resource != null ) { resource.setResourceListener(key, this ); if (resource.isCacheable()) { activeResources.activate(key, resource); } } jobs.removeIfCurrent(key, engineJob); }
加载完成后,把对应资源插入到ActiveResources
中作为活动资源。
Glide高级用法 处理带有后缀的图片类型,可能为了保证安全,不同的用户获取的图片除了图片地址外还会有一段标识用户的token。而且token并不一定是固定的,这样我们再去加载图片时,由于缓存key不一致,导致重复加载。
这里涉及到了缓存key 的生成,其中有一个重要参数为远程图片加载地址,对于上述情况,因为地址的变化,key不同则查找缓存时也无法命中,解决这个情况就需要排除掉变化的部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class MyGlideUrl extends GlideUrl { private String mUrl; public MyGlideUrl (String url) { super (url); mUrl = url; } @Override public String getCacheKey () { return mUrl.replace(replaceTokenParam(),"" ); } private String replaceTokenParam () { String tokenParam="" ; int tokenIndex = mUrl.contains("?.token" ) ? mUrl.indexOf("?token" ):mUrl.indexOf("&token" ); if (tokenIndex!=-1 ){ int nextAndIndex = mUrl.indexOf("&" ,tokenIndex+1 ); if (nextAndIndex!=-1 ){ tokenParam = mUrl.substring(tokenIndex+1 ,nextAndIndex+1 ); }else { tokenParam = mUrl.substring(tokenIndex); } } return tokenParam; } } Glide.with(mContext).load(MyGlideUrl(imgUrl)).into(imageView);
内容引用 Glide主流源码分析
Glide4.8源码拆解(二)核心加载流程