Glide是一个图片加载框架,其他的图片加载框架还有UniversalImageLoader,Picasso,Fresco等,个人还是比较喜欢Glide这个框架的。Glide致力于打造更好的列表图片滑动体验,就如他的名字Glide(滑翔)一样顺畅,Glide还支持加载video,Gif,SVG格式。而且Glide会与你的Activity/Fragment绑定相关的生命周期,有自己的缓存策略,这样就让图片加载操作变得非常简单。本文的Glide源码是4.0的版本(我本来以为是3.7.0来着,后来一看有些代码对不上……)。
准备工作 如果你还没有使用过glide,可以通过下面两句话引入glide:
1 2 compile 'com.github.bumptech.glide:glide:3.7.0' compile 'com.android.support:support-v4:19.1.0'
编译源码: 在阅读源码的时候,难免希望自己能加上几个log或者自己加点注释之类的来方便自己阅读。可以通过如下方式编译glide源码:
1 2 3 4 git clone git@github.com:bumptech/glide.git # use https://github.com/bumptech/glide.git if "Permission Denied" cd glide git submodule init && git submodule update ./gradlew jar
不过说实话,我按这个流程操作了几次才成功。编译成功之后你就可以运行sample和尽情的修改glide源码了。
如何打开Glide的log,这个官方仓库里有介绍,直接放上链接:Debugging and Error Handling
从最简流程切入读源码 我们用Glide加载一张图,最简单的代码是怎样的呢?
1 Glide.with(Activity).load(url).into(imageview);
因为流式api,整个调用流程显得非常简洁、简单,但是这短短的几个方法调用里,涉及到的东西却是非常之多的,所以看累了的话,可以起来走走,喝点水……
在正式看代码之前,先上一下Glide的设计图: 这图也不是我画的,我看到了几篇文都有这图,这图画得很好,文末会给出参考资料链接。
上面的东西,刚接触肯定是很陌生的。不过没事,大概知道有这么些个东西就好了。那么正式开始看代码吧,首先是Glide.with(),点进去看看:
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 static RequestManager with (Context context) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(context); } public static RequestManager with (Activity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); } public static RequestManager with (FragmentActivity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); } public static RequestManager with (android.app.Fragment fragment) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(fragment); } public static RequestManager with (Fragment fragment) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(fragment); }
可以看到with有多个重载方法,适配了各种可能出现的情况。 继续追踪源码:
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 public RequestManager get (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); } public RequestManager get (FragmentActivity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); FragmentManager fm = activity.getSupportFragmentManager(); return supportFragmentGet(activity, fm, null ); } } public RequestManager get (Fragment fragment) { if (fragment.getActivity() == null ) { throw new IllegalArgumentException ( "You cannot start a load on a fragment before it is attached" ); } if (Util.isOnBackgroundThread()) { return get(fragment.getActivity().getApplicationContext()); } else { FragmentManager fm = fragment.getChildFragmentManager(); return supportFragmentGet(fragment.getActivity(), fm, fragment); } } public RequestManager get (Activity activity) { if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); android.app.FragmentManager fm = activity.getFragmentManager(); return fragmentGet(activity, fm, null ); } }
先不看参数是context的方法,看一下get(FragmentActivity activity)这个方法,首先判断是否在主线程,如果是的话调用supportFragmentGet方法,看下这个方法的代码:
1 2 3 4 5 6 7 8 9 10 11 12 RequestManager supportFragmentGet (Context context, FragmentManager fm, Fragment parentHint) { SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint); RequestManager requestManager = current.getRequestManager(); if (requestManager == null ) { Glide glide = Glide.get(context); requestManager = new RequestManager (glide, current.getLifecycle(), current.getRequestManagerTreeNode()); current.setRequestManager(requestManager); } return requestManager; }
这个方法里有一个SupportRequestManagerFragment(以下简称SRMFragment,如果参数是Activity或者app包中的Fragment,则是RequestManagerFragment)。这个SRMFragment是一个不可见的Fragment,用来和你的Fragment/Activity的生命周期关联起来。如何关联呢?通过ChildFragmentManager/FragmentManager,将这个Fragment添加到Fragment/Activity中,最终将生命周期传递到RequestManager中,让RequestManager对不同的状态做相应的处理。对于内存较低的情况,SRMFragment也有相应的周期。关于SRMFragment的简单介绍便到此为止。接着获取Glide和RequestManager对象,首先是glide:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public static Glide get (Context context) { if (glide == null ) { synchronized (Glide.class) { if (glide == null ) { Context applicationContext = context.getApplicationContext(); List<GlideModule> modules = new ManifestParser (applicationContext).parse(); GlideBuilder builder = new GlideBuilder (applicationContext); for (GlideModule module : modules) { module .applyOptions(applicationContext, builder); } glide = builder.createGlide(); for (GlideModule module : modules) { module .registerComponents(applicationContext, glide.registry); } } } } return glide; }
很明显是单例的写法,采用双重校验锁的方式。接着是构造RequestManager对象。在Glide中,加载图片是以Request的形式交给Engine去处理的。而RequestManager是为Glide管理和开启请求的类,可以通过Activity/Fragment/Connectivity(网络连接监听)的生命周期方法进行stop,start,restart。
上面有一个参数为Context的get方法略过了,但是其实跟上面介绍的也差不多,只不过如果不是FragmentActivity、Activity和ContextWrapper的对象的引用,则会调用getApplicationManager方法,看一下这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private RequestManager getApplicationManager (Context context) { if (applicationManager == null ) { synchronized (this ) { if (applicationManager == null ) { Glide glide = Glide.get(context); applicationManager = new RequestManager ( glide, new ApplicationLifecycle (), new EmptyRequestManagerTreeNode ()); } } } return applicationManager; }
可以看到也是获取了Glide和RequestManager对象,上面的注释比较简单就不翻译了,简单的解释了用这个context的生命周期的问题。至此简单的分析了Glide.with()方法,这个方法将Glide的生命周期与我们的程序相关联,让我们无需考虑各种复杂的情况。Glide.with()返回的是一个RequestManager方法,接下来就是分析Glide.with().load()了,很显然在RequestManager内:
1 2 3 public RequestBuilder<Drawable> load (@Nullable Object model) { return asDrawable().load(model); }
我就是在这发现我看的好像是假的源码,我从glide仓库clone编译的源码,发现跟我原来项目里引用的源码有些不一样,后来看了一下……果然版本不一样:
在3.7.0的源码中有好几个load的重载方法,但是在最新的代码中只有这一个load方法,更多的load的重载方法在RequestBuilder中了,大概是想让各个类的职责更加清晰一点吧。那么就进RequestBuilder看看几个load方法吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public RequestBuilder load (@Nullable Object model) { return loadGeneric(model); } public RequestBuilder load (@Nullable String string) { return loadGeneric(string); } public RequestBuilder load (@Nullable Uri uri) { return loadGeneric(uri); } public RequestBuilder load (@Nullable File file) { return loadGeneric(file); } public RequestBuilder load (@Nullable Integer resourceId) { return loadGeneric(resourceId).apply(signatureOf(ApplicationVersionSignature.obtain(context))); } @Deprecated public RequestBuilder load (@Nullable URL url) { return loadGeneric(url); } public RequestBuilder load (@Nullable byte [] model) { return loadGeneric(model).apply(signatureOf(new ObjectKey (UUID.randomUUID().toString())) .diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true )); }
这么多重载方法,最终都调用了loadGeneric方法:
1 2 3 4 5 private RequestBuilder loadGeneric (@Nullable Object model) { this .model = model; isModelSet = true ; return this ; }
仅仅是设置了两个字段的值,那么继续看into方法,还是在RequestBuilder中:
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 public Target<TranscodeType> into (ImageView view) { Util.assertMainThread(); Preconditions.checkNotNull(view); if (!requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed() && view.getScaleType() != null ) { if (requestOptions.isLocked()) { requestOptions = requestOptions.clone(); } switch (view.getScaleType()) { case CENTER_CROP: requestOptions.optionalCenterCrop(context); break ; case CENTER_INSIDE: requestOptions.optionalCenterInside(context); break ; case FIT_CENTER: case FIT_START: case FIT_END: requestOptions.optionalFitCenter(context); break ; default : } } return into(context.buildImageViewTarget(view, transcodeClass)); }
根据ImageView的scaleType进行了一些配置,这里通过glideContext生成了一个ViewTarget。在Glide中Target是资源加载的目标,最后调用了into重载方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public <Y extends Target <TranscodeType>> Y into (@NonNull Y target) { Util.assertMainThread(); Preconditions.checkNotNull(target); if (!isModelSet) { throw new IllegalArgumentException ("You must call #load() before calling #into()" ); } Request previous = target.getRequest(); if (previous != null ) { requestManager.clear(target); } requestOptions.lock(); Request request = buildRequest(target); target.setRequest(request); requestManager.track(target, request); return target; }
调用了buildRequest方法,看下这个方法和这个方法调用的方法:
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 Request buildRequest (Target<TranscodeType> target) { return buildRequestRecursive(target, null , transitionOptions, requestOptions.getPriority(), requestOptions.getOverrideWidth(), requestOptions.getOverrideHeight()); } private Request buildRequestRecursive (Target<TranscodeType> target, @Nullable ThumbnailRequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight) { 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 (DEFAULT_ANIMATION_OPTIONS.equals(thumbTransitionOptions)) { thumbTransitionOptions = transitionOptions; } Priority thumbPriority = thumbnailBuilder.requestOptions.isPrioritySet() ? thumbnailBuilder.requestOptions.getPriority() : getThumbnailPriority(priority); int thumbOverrideWidth = thumbnailBuilder.requestOptions.getOverrideWidth(); int thumbOverrideHeight = thumbnailBuilder.requestOptions.getOverrideHeight(); if (Util.isValidDimensions(overrideWidth, overrideHeight) && !thumbnailBuilder.requestOptions.isValidOverride()) { thumbOverrideWidth = requestOptions.getOverrideWidth(); thumbOverrideHeight = requestOptions.getOverrideHeight(); } ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator (parentCoordinator); Request fullRequest = obtainRequest(target, requestOptions, coordinator, transitionOptions, priority, overrideWidth, overrideHeight); isThumbnailBuilt = true ; Request thumbRequest = thumbnailBuilder.buildRequestRecursive(target, coordinator, thumbTransitionOptions, thumbPriority, thumbOverrideWidth, thumbOverrideHeight); isThumbnailBuilt = false ; coordinator.setRequests(fullRequest, thumbRequest); return coordinator; } else if (thumbSizeMultiplier != null ) { ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator (parentCoordinator); Request fullRequest = obtainRequest(target, requestOptions, coordinator, transitionOptions, priority, overrideWidth, overrideHeight); BaseRequestOptions<?> thumbnailOptions = requestOptions.clone() .sizeMultiplier(thumbSizeMultiplier); Request thumbnailRequest = obtainRequest(target, thumbnailOptions, coordinator, transitionOptions, getThumbnailPriority(priority), overrideWidth, overrideHeight); coordinator.setRequests(fullRequest, thumbnailRequest); return coordinator; } else { return obtainRequest(target, requestOptions, parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight); } }
buildRequest创建了请求,如果配置了缩略图请求,那么会生成一个ThumbnailRequestCoordinator请求。这个请求内部包含了一个FullRequest和ThumbnailRequest。如果没有配置,则通过obtainRequest方法生成一个SingleRequest对象返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private Request obtainRequest (Target<TranscodeType> target, BaseRequestOptions<?> requestOptions, RequestCoordinator requestCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight) { requestOptions.lock(); return SingleRequest.obtain( context, model, transcodeClass, requestOptions, overrideWidth, overrideHeight, priority, target, requestListener, requestCoordinator, context.getEngine(), transitionOptions.getTransitionFactory()); }
看完了buildRequest方法,接着看requestManager.track(target,requst),这个方法调用了RequestTrack的runRequest方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 void track (Target<?> target, Request request) { targetTracker.track(target); requestTracker.runRequest(request); } public void runRequest (Request request) { requests.add(request); if (!isPaused) { request.begin(); } else { pendingRequests.add(request); } }
request.biegin调用的是SingleRequest的begin方法,begin调用了onSizeReady方法而onSizeReady又调用了engine.load()方法。至此,终于摸到了真正加载的门槛了:
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 public <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, Options options, boolean isMemoryCacheable, boolean useUnlimitedSourceExecutorPool, boolean onlyRetrieveFromCache, ResourceCallback cb) { Util.assertMainThread(); long startTime = LogTime.getLogTime(); EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options); EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); if (cached != null ) { cb.onResourceReady(cached, DataSource.MEMORY_CACHE); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from cache" , startTime, key); } return null ; } EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); if (active != null ) { cb.onResourceReady(active, DataSource.MEMORY_CACHE); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from active resources" , startTime, key); } return null ; } EngineJob<?> current = jobs.get(key); if (current != null ) { current.addCallback(cb); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Added to existing load" , startTime, key); } return new LoadStatus (cb, current); } EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable, useUnlimitedSourceExecutorPool); DecodeJob<R> decodeJob = decodeJobFactory.build( glideContext, model, key, signature, width, height, resourceClass, transcodeClass, priority, diskCacheStrategy, transformations, isTransformationRequired, onlyRetrieveFromCache, options, engineJob); jobs.put(key, engineJob); engineJob.addCallback(cb); engineJob.start(decodeJob); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Started new load" , startTime, key); } return new LoadStatus (cb, engineJob); }
可以看到首先从内存缓存中获取资源,其次从存活的资源中加载缓存,这么做可以提高命中率。内存缓存使用的是LruResourceCache继承自LruCache(lru,最近最少使用),当然了,这个LruCache也是glide内部自己实现的一个,现在还不必深入去看怎么实现的知道就行。如果loadFromCache命中,那么会将资源放入activeResources中,同时将资源从LruCache中移除。命中后会直接调用ResourceCallback回调方法onResourceReady,而最终又会调用target的onResourceReady方法,继续看下去就会发现最终的实现类调用了view.setImageBitmap(BitmapImageViewTarget)或者view.setImageDrawable(DrawableImageViewTarget)。另外一个内存缓存用弱引用缓存当前正在使用的资源,回调方式和之前的LruCache是一样的,不做更多的介绍了。
前面说的都是命中的情况,接着看未命中的。内存中读取数据都没有命中的话,则会生成EngineJob和DecodeJob。EngineJob的职责是调度DecodeJob,添加,移除资源回调,并notify回调。DecodeJob负责从缓存资源或者原始数据中读取资源,Glide中的脏累活基本都是这个DecodeJob干的。回到代码,最后调用了engineJob.start方法,看代码:
1 2 3 4 5 6 7 public void start (DecodeJob<R> decodeJob) { this .decodeJob = decodeJob; GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); executor.execute(decodeJob); }
这个GlideExecutor是一个线程池,而DecodeJob是实现了Runnable接口的类,所以看一下DecodeJob的run方法:
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 public void run () { try { if (isCancelled) { notifyFailed(); return ; } runWrapped(); } catch (RuntimeException e) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "DecodeJob threw unexpectedly" + ", isCancelled: " + isCancelled + ", stage: " + stage, e); } if (stage != Stage.ENCODE) { notifyFailed(); } if (!isCancelled) { throw e; } } } 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 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 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); } }
主要的加载逻辑就在这几个方法里。这个runReason初始值就是INITIALIZE,进入这个case首先调用了getNextStage方法,获取到Stage然后根据Stage获取相应的Generator,最后执行Generator。一共有三种Generator:
ResourceCacheGenerator:从处理过的缓存加载数据
DataCacheGenerator:从原始缓存加载数据
SourceGenerator:从数据源请求数据
上面提到执行Generator,会调用currentGenerator.startNext方法,这里主要看一下SourceGenerator的starNext方法:
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 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; }
前面老长一段先不看了,第一次加载肯定是null,直接看后面,首先是getLoadData:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 List<LoadData<?>> getLoadData() { if (!isLoadDataSet) { isLoadDataSet = true ; loadData.clear(); List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model); int size = modelLoaders.size(); for (int i = 0 ; i < size; i++) { ModelLoader<Object, ?> modelLoader = modelLoaders.get(i); LoadData<?> current = modelLoader.buildLoadData(model, width, height, options); if (current != null ) { loadData.add(current); } } } return loadData; }
通过glide的上下文获取到所有能处理Model类型的注册过的ModelLoader,遍历这些ModelLoader,通过buildLoadData生成LoadData,最终返回一个LoadData的列表。loadData咋来的弄清楚了,接着看重点了,loadData,这一看就是加载数据的方法了。由于Glide适配了多种网络请求框架,这基本都是用的接口来解耦,看起来真的挺蛋疼的……关于fetcher的实现类就不去分析了,直接看数据加载成功的回调就好。上面的代码是将SourceGenertor自身传递进去作为回调,直接看回调方法:
1 2 3 4 5 6 7 8 9 10 11 12 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); } }
这里调用了reschedule,重新调度当前任务,这个时候我们前面忽略的代码就起作用了,会进行写缓存的操作。这之后会切换加载的策略,最终获取数据成功时会调用onDataFecherReady,这个方法又会调用decodeFromRetrieveData方法,这个方法又调用了decodeFromData,这个方法又调用了decodeFromFetcher(有完没完了……)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 { DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data); try { return path.load(rewinder, options, width, height, new DecodeCallback <ResourceType>(dataSource)); } finally { rewinder.cleanup(); } }
看到这我真是无语了,又是一堆看不懂的……我能怎么办啊,我也很绝望啊!不过行百里者半九十(虽然可能连60都没……),咬咬牙就挺过去了~
里面涉及到的东西,一个一个的简介:
LoadPath:根据给定的数据类型的DataFetcher尝试获取数据,然后尝试通过一个或多个decodePath进行decode
DecodePath:根据指定的数据类型对resource进行decode和transcode
DataRewinder:负责将流转换成数据类型
最终在run方法里开始了最终的加载,传入的参数是DecodeJob的内部类,实现了DecodePath.DecodeCallback,看一下最终的回调方法:
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 public Resource<Z> onResourceDecoded (Resource<Z> decoded) { Class<Z> resourceSubClass = getResourceClass(decoded); Transformation<Z> appliedTransformation = null ; Resource<Z> transformed = decoded; if (dataSource != DataSource.RESOURCE_DISK_CACHE) { appliedTransformation = decodeHelper.getTransformation(resourceSubClass); transformed = appliedTransformation.transform(decoded, width, height); } if (!decoded.equals(transformed)) { decoded.recycle(); } final EncodeStrategy encodeStrategy; final ResourceEncoder<Z> encoder; if (decodeHelper.isResourceEncoderAvailable(transformed)) { encoder = decodeHelper.getResultEncoder(transformed); encodeStrategy = encoder.getEncodeStrategy(options); } else { encoder = null ; encodeStrategy = EncodeStrategy.NONE; } Resource<Z> result = transformed; boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey); if (diskCacheStrategy.isResourceCacheable(isFromAlternateCacheKey, dataSource, encodeStrategy)) { if (encoder == null ) { throw new Registry .NoResultEncoderAvailableException(transformed.get().getClass()); } final Key key; if (encodeStrategy == EncodeStrategy.SOURCE) { key = new DataCacheKey (currentSourceKey, signature); } else if (encodeStrategy == EncodeStrategy.TRANSFORMED) { key = new ResourceCacheKey (currentSourceKey, signature, width, height, appliedTransformation, resourceSubClass, options); } else { throw new IllegalArgumentException ("Unknown strategy: " + encodeStrategy); } LockedResource<Z> lockedResult = LockedResource.obtain(transformed); deferredEncodeManager.init(key, encoder, lockedResult); result = lockedResult; } return result; }
最后还是回到了decodeFromRetrievedData:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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); exceptions.add(e); } if (resource != null ) { notifyEncodeAndRelease(resource, currentDataSource); } else { runGenerators(); } }
notifyEncodeAndRelease中处理了对处理过的图片的缓存操作。当缓存完成后(如果有需要的话)就通过回调告诉外面加载完成了。至此,整个加载过程完成。
后记 这里只是简单的过了一遍最简的调用所经历的过程,但是这中间涉及到的东西真的很多。Glide用起来还是挺方便的,由于需要考虑各种情况和适配不同的网络请求框架,内部采用了各种接口解耦,读的时候这也算是比较痛苦的一点吧,往往得往前追溯几个类你才能知道这个实现类是什么。不过Glide还是很值得我们去学习一下,阅读一下的,以后我也会更加深入的去阅读Glide。
参考资料 Glide源码之生命周期
Glide源码分析
Glide官方仓库
如何调试Glide加载图片
Glide源码导读