Glide缓存机制Glide缓存机制Glide缓存机制　简介内存缓存的取资源第一步:获取缓存key第二步:从弱引用缓存中获取loadFromActiveResources()第三步:从内存LruCache中获取loadFromCache()...　Glide缓存机制　Glide缓存机制简介　Glide的缓存分为两种,一种是内存缓存,一种是硬盘缓存,其中内存缓存包含弱引用缓存HashMap和LruCache,硬盘缓存就是DiskLruCache。获取缓存的顺序是先去弱引用缓存中寻找,没有再去LruCache中寻找,内存缓存中没有则取硬盘缓存中寻找,如果内存缓存和硬盘缓存中都没有该图片,则再通过HttpUrlConnection新建网络请求去获取图片资源。　内存缓存的取资源　在上一篇博客的介绍中,我们知道Glide请求流程的最后只通过调用Engine的load方法来真正开始加载的逻辑,所以自然而然读缓存的操作也是从Engine的load方法中开始:　public　synchronized　<　R　>　LoadStatus　load　获取资源的　key　,参数有8个EngineKey　key　=　keyFactory　.　buildKey　(　model　,　signature　,　width　,　height　,　transformations　,　resourceClass　,　transcodeClass　,　options　)　;　EngineResource　<　?　>　memoryResource　;　synchronized　(　this　)　{　//去内存中获取　memoryResource　=　loadFromMemory　(　key　,　isMemoryCacheable　,　startTime　)　}　//　如果都获取不到,则去硬盘缓存或网络加载　由以上几行代码,我们把内存缓存的步骤分成以下几步来解析　第一步:获取缓存key　//　获取资源的　key　,参数有8个EngineKey　key　=　keyFactory　.　buildKey　(　model　,　signature　,　width　,　height　,　transformations　,　resourceClass　,　transcodeClass　,　options　)　;　我们看到,在创建key的时候,会传入8个参数,所以及时我们每次要获取的是同一张图片,但是大小不一样的话,也会生成一个新的缓存key。去进行缓存。　Glide是默认开启内存缓存的,如果我们想关掉内存缓存,可以调用:　//关闭内存缓存　skipMemoryCache　(　false　)　第二步:从弱引用缓存中获取　EngineResource　<　?　>　active　=　loadFromActiveResources　(　key　,　isMemoryCacheable　)　;　调用了loadFromActiveResources()方法。　loadFromActiveResources()　@Nullable　private　EngineResource　<　?　>　loadFromActiveResources　(　Key　key　,　boolean　isMemoryCacheable　)　{　if　(　!　isMemoryCacheable　)　{　return　null　;　}　//去弱引用activeResources这个HashMap中获取　EngineResource　<　?　>　active　=　activeResources　.　get　(　key　)　;　//如果能拿到资源,调用acquire()方法令计数器　+1　if　(　active　!=　null　)　{　active　.　acquire　(　)　;　}　return　active　;　}　@Nullable　synchronized　EngineResource　<　?　>　get　(　Key　key　)　{　ResourceWeakReference　activeRef　=　activeEngineResources　.　get　(　key　)　;　if　(　activeRef　==　null　)　{　return　null　;　}　EngineResource　<　?　>　active　=　activeRef　.　get　(　)　;　//如果没有查询到此弱引用对象,则删除此key　if　(　active　==　null　)　{　cleanupActiveReference　(　activeRef　)　;　}　return　active　;　}　synchronized　void　acquire　(　)　{　if　(　isRecycled　)　{　throw　new　IllegalStateException　(　"Cannot　acquire　a　recycled　resource"acquired　;　}　这个方法就是去弱引用的activeResources这个HashMap中通过key拿到弱引用的对象,如果获取不到,则队形可能被GC,就从map中移除这个key;如果获取到则调用acquire()方法,令计数器acquire加1,代表被使用,关于计数器的应用,我们最后会总结。　第三步:从内存LruCache中获取　//　从lrucache　获取对象　EngineResource　<　?　>　cached　=　loadFromCache　(　key　,　isMemoryCacheable　)　;　调用了loadFromCache方法　loadFromCache()　private　EngineResource　<　?　>　loadFromCache　(　Key　key　,　boolean　isMemoryCacheable　)　{　if　(　!　isMemoryCacheable　)　{　return　null　;　}　//根据key去内存中获取资源　EngineResource　<　?　>　cached　=　getEngineResourceFromCache　(　key　)　;　//如果获取到了资源,令其计数器加1,并且存放到弱引用缓存中　if　(　cached　!=　null　)　{　cached　.　acquire　(　)　;　activeResources　.　activate　(　key　,　cached　)　;　}　return　cached　;　}　getEngineResourceFromCache()　private　EngineResource　<　?　>　getEngineResourceFromCache　(　Key　key　)　{　//调用的remove方法去获取,也就是说,获取到资源之后,会把此资源从LruCache中移除　Resource　<　?　>　cached　=　cache　.　remove　(　key　)　;　final　EngineResource　<　?　>　result　;　if　(　cached　==　null　)　{　result　=　null　;　}　else　if　(　cached　instanceof　EngineResource　)　{　//Save　an　object　allocation　if　we've　cached　an　EngineResource　(the　typical　case).　result　=　(　EngineResource　cached　;　}　else　{　result　=　new　EngineResource　<　>　(　cached　,　/*isMemoryCacheable=*/　true　,　/*isRecyclable=*/　true　,　key　,　/*listener=*/　this　)　;　}　return　result　;　}　通过以上两个方法,我们得知从LruCache中获取资源,是首先通过remove方法获取资源,获取到之后将资源从LruCache中移除,令其计数器加1并将此资源存入弱缓存中。　至此,我们就过了一遍内存缓存的拿取资源的流程:先从弱引用中取对象,如果存在,引用计数+1,如果不存在,从LruCache　取,如果存在,则引用计数+1,并把它存到弱引用中,且自身从　LruCache　移除。　内存缓存的存资源　存储资源也一定是在图片加载的方法Engine的load方法中进行存储。我们看一下:　Engine.load()　public　synchronized　<　R　>　LoadStatus　load　获取　key　EngineKey　key　=　keyFactory　.　buildKey　(　model　,　signature　,　width　,　height　,　transformations　,　resourceClass　,　transcodeClass　,　options　)　;　//　从　弱引用中获取对象　EngineResource　<　?　>　active　=　loadFromActiveResources　(　key　,　isMemoryCacheable　从LruCache　获取对象　EngineResource　<　?　>　cached　=　loadFromCache　(　key　,　isMemoryCacheable　EngineJob　<　R　>　engineJob　=　engineJobFactory　.　build　(　key　,　isMemoryCacheable　,　useUnlimitedSourceExecutorPool　,　useAnimationPool　,　onlyRetrieveFromCache　)　;　DecodeJob　<　R　>　decodeJob　=　decodeJobFactory　.　build　(　glideContext　,　model　,　key　,　signature　,　width　,　height　,　resourceClass　,　transcodeClass　,　priority　,　diskCacheStrategy　,　transformations　,　isTransformationRequired　,　isScaleOnlyOrNoTransform　,　onlyRetrieveFromCache　,　options　,　engineJob　)　;　jobs　.　put　(　key　,　engineJob　)　;　engineJob　.　addCallback　(　cb　,　callbackExecutor　)　;　engineJob　.　start　(　decodeJob　这里会创建两个关键的对象,一个是EngineJob,这是一个线程池,维护了编码、资源解析、网络下载等工作;另一个是DecodeJob,用来对图片进行解码,它继承了Runnable,相当于EngineJob的一个任务。然后调用engineJob.start(decodeJob),具体细节先不说,等方法结束过后,会回调onResourceReady()方法　onResourceReady()　@Override　public　void　onResourceReady　(　Resource　<　R　>　resource　,　DataSource　dataSource　)　{　synchronized　(　this　)　{　this　.　resource　=　resource　;　this　.　dataSource　=　dataSource　;　}　notifyCallbacksOfResult　(　)　;　}　notifyCallbacksOfResult()　@Synthetic　void　notifyCallbacksOfResult　(　)　{　ResourceCallbacksAndExecutors　copy　;　Key　localKey　;　EngineResource　<　?　>　localResource　;　synchronized　(　this　)　{　stateVerifier　.　throwIfRecycled　(　)　;　//是否被取消　if　(　isCancelled　)　{　resource　.　recycle　(　)　;　release　(　)　;　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　;　copy　=　cbs　.　copy　引用计数　+1　incrementPendingCallbacks　(　copy　.　size　(　)　+　1　)　;　localKey　=　key　;　localResource　=　engineResource　;　}　//　把对象put到弱引用上　listener　.　onEngineJobComplete　(　this　,　localKey　,　localResource　)　;　//　遍历所有图片　for　(　final　ResourceCallbackAndExecutor　entry　:　copy　)　{　//　把资源加载到　imageview　中,引用计数　+1　entry　.　executor　.　execute　(　new　CallResourceReady　(　entry　.　cb　引用计数　-1　decrementPendingCallbacks　(　)　;　}　从上面看,notifyCallbacksOfResult()　方法做了以下事情　图片的引用计数　+1　通过　listener.onEngineJobComplete()　,它的回调为　Engine.onEngineJobComplete(),把资源　put　到　弱引用上　遍历加载的图片,如果加载成功,则引用计数+1,且通过　cb.onResourceReady(engineResource,　dataSource)　回调给　target　(imageview)　去加载　通过　decrementPendingCallbacks()　释放资源,引用计数　-1　当引用计数减到　0　时,即图片已经没有使用时,就会调用　onResourceReleased()　接口　onResourceReleased()　@Override　public　synchronized　void　onResourceReleased　(　Key　cacheKey　,　EngineResource　<　?　>　resource　)　{　//　从弱引用中移除　activeResources　.　deactivate　(　cacheKey　)　;　if　(　resource　.　isCacheable　添加到　LruCache　中cache　.　put　(　cacheKey　,　resource　)　;　}　else　{　//　回收资源　resourceRecycler　.　recycle　(　resource　)　;　}　}　磁盘缓存　如果在内存缓存中拿不到图片,此时Glide就会从两个方面来进行判断:　一个是资源类型:该图片是否之前曾被解码、转换并写入过磁盘缓存。　一个是数据来源:构建这个图片的资源是否之前被写入过文件缓存。　我们的硬盘缓存;Glide　的硬盘策略可以分为如下几种:　DiskCacheStrategy.RESOURCE　:只缓存解码过的图片　DiskCacheStrategy.DATA　:只缓存原始图片　DiskCacheStrategy.ALL　:　即缓存原始图片,也缓存解码过的图片啊,　对于远程图片,缓存　DATA　和RESOURCE;对本地使用　只缓存　RESOURCE。　DiskCacheStrategy.NONE　:不使用硬盘缓存　DiskCacheStrategy.AUTOMATIC　:默认策略,会对本地和和远程图片使用最佳的策略;对下载网络图片,使用　DATA,对于本地图片,使用　RESOURCE　在讲述磁盘缓存的源码时,先附一张流程图:　从上面我们知道,一个图片的加载在　DecodeJob　这个类中,这个任务由　EngineJob　这个线程池去执行的。去到　run　方法,可以看到有个　runWrapped()　方法:　runWrapped()　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　)　;　}　刚开始　runReason　初始化为　INITIALIZE　,　所以它会走第一个　case。　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　:　//　Skip　loading　from　source　if　the　user　opted　to　only　retrieve　the　resource　from　cache.　return　onlyRetrieveFromCache　?　Stage　.　FINISHED　:　Stage　.　SOURCE　;　case　SOURCE　:　case　FINISHED　:　return　Stage　.　FINISHED　;　default　:　throw　new　IllegalArgumentException　(　"Unrecognized　stage:　"　+　current　)　;　}　}　getNextStage　其实就是对当前的缓存策略进行判断,由于我们的策略为DiskCacheStrategy.ALL　,所以　diskCacheStrategy.decodeCachedResource()　永远为true,即会解析解码的流程即去尝试拿磁盘中解码过的图片资源,所以　State　被赋值为　Stage.RESOURCE_CACHE(State是一个标记)。接着回到runWrapped()方法中,继续执行调用　currentGenerator　=　getNextGenerator()　拿到当前的解码器为　ResourceCacheGenerator,然后调用runGenerators()方法,这个方法是关键:　runGenerators()　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　这里面维护了一个while循环,不断的通过　调用当前解码器的startNext()　方法取尝试从DiskLruCache中拿到对象,如果拿不到,则通过while循环通过getNextstage(stage)和getNextGenerator()方法拿到下一个解码器再次寻找,当stage　==　Stage.SOURCE　的时候,会调用reschedule()重新调用DecodeJob的run方法重新进行RunWrapper方法。　startNext()　@Override　public　boolean　startNext　(　)　{　List　<　Key　>　sourceIds　=　helper　.　getCacheKeys　while　(　modelLoaders　==　null　||　!　hasNextModelLoader　resourceClassIndex　++　;　if　(　resourceClassIndex　>=　resourceClasses　.　size　sourceIdIndex　++　;　//　由于没有缓存,最后会在这里退出这个循环　if　(　sourceIdIndex　>=　sourceIds　.　size　(　)　)　{　return　false　;　}　resourceClassIndex　=　0　;　}　Key　sourceId　=　sourceIds　.　get　(　sourceIdIndex　)　;　//获取缓存　key　currentKey　=　new　ResourceCacheKey　(　//　NOPMD　AvoidInstantiatingObjectsInLoops　helper　.　getArrayPool　(　)　,　sourceId　,　helper　.　getSignature　(　)　,　helper　.　getWidth　(　)　,　helper　.　getHeight　(　)　,　transformation　,　resourceClass　,　helper　.　getOptions　尝试从　DiskLruCache　拿数据　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　;　}　由于第一次肯定是拿不到缓存的,所以　while　(modelLoaders　==　null　||　!hasNextModelLoader())　循环会一直运行,直到返回　false。　同理,接着来拿到了DataCacheGenerator之后也是同样,最后,　当stage　==　Stage.SOURCE　的时候,才会退出,并调用reschedule()　方法　。　@Override　public　void　reschedule　(　)　{　runReason　=　RunReason　.　SWITCH_TO_SOURCE_SERVICE　;　callback　.　reschedule　(　this　)　;　}　在reschedule()　方法中,会把　runReason　的状态改成RunReason.SWITCH_TO_SOURCE_SERVICE　,并重新回调　run　方法,又会调用　runWrapped()　方法,但此时的　runReason　已经变成了　SWITCH_TO_SOURCE_SERVICE,所以它会执行　runGenerators()　方法(代码上面有):　此时当前解码器currentGenerator,并不为null,所以此时会调用SourceGenerator的startNext()方法:　@Override　public　boolean　startNext　(　)　{　if　(　dataToCache　!=　null　)　{　Object　data　=　dataToCache　;　dataToCache　=　null　;　//　存储到　DiskLruCache　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　;　}　首先它会判断　dataToCache　是否为　null,第一次肯定会　null,所以,可以先不管。由于还并没有给sourceCacheGenerator赋值,所以它为null,这里可以直接看　loadData.fetcher.loadData();　这个方法,loadData()　是个接口,它有很多个实现方法,由于我们这里是网络下载,所以去到　HttpUrlFetcher.loadData()　中:　loadData()　@override　public　void　loadData　(　@NonNull　Priority　priority　,　@NonNull　Datacallback　<　?　super　Inputstream　>　callback　)　{　long　startTime　=　LogTime　.　getLogTime　(　)　;　try　{　Inputstream　result　=　loadDatawithRedirects　(　glideur1　.　toURL　(　)　,　0　,　null　,glideur1　.　getHeaders　callback　.　onDataReady　(　result　)　;　}　catch　(　TOException　e　)　{　if　(　Log　.　isLoggable　(　TAG,　Log　.　DEBUG　)　)　Log　.　d　(　TAG,msg　:　"Failed　to　load　data　for　ur1"　,　e　)　;　}　}　可以看到,它拿到　inputStream　后,通过　onDataReady()　方法回调回去　@Override　public　void　onDataReady　(　Object　data　)　{　DiskCacheStrategy　diskCacheStrategy　=　helper　.　getDiskCacheStrategy　(　)　;　if　(　data　!=　null　&&　diskCacheStrategy　.　isDataCacheable　(　loadData　.　fetcher　.　getDataSource　dataToCache　=　data　;　//　We　might　be　being　called　back　on　someone　else's　thread.　Before　doing　anything,　we　should　//　reschedule　to　get　back　onto　Glide's　thread.　cb　.　reschedule　(　)　;　}　else　{　cb　.　onDataFetcherReady　(　loadData　.　sourceKey　,　data　,　loadData　.　fetcher　,　loadData　.　fetcher　.　getDataSource　(　)　,　originalKey　)　;　}　}　在SourceGenerator.onDataReady()　中,对dataToCache　进行赋值;然后又调用　cb.reschedule()方法,从头再来一次,可是这一次dataToCache已经不是null了,所以会执行cacheData方法(代码逻辑在上面有):　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,msg　:　"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,cb　:　this　)　;　}　可以看到,对这个已经解析完的数据,通过　helper.getDiskCache().put()　方法,存到到　DiskLruCache　硬盘缓存中。并通过　loadData.fetcher.clearup()　清除任务,把sourcecacheGenerator赋值为　DataCacheGenerator。　回到SourceGenerator的startNext方法　@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　:　}　此时　sourceCacheGenerator　不为　null,所以会走　DataCacheGenerator　的startNext()　方法。　在这之前已经将网络请求获取的图片加载到DiskLruCache中了,所以已经拿到了请求的图片资源,之后就会经过一系列的调用,调用到EngineJob的onResourceReady方法,这个方法我们在内存缓存的时候说过,它会把资源存放到弱引用中并且加载图片。　想必通过上面的一堆代码展示,对于硬盘的缓存的理解还是会模糊,所以我们在下面总结一下。　硬盘缓存小结　总结一下硬盘缓存的步骤:　一:根据硬盘策略,选择不同的缓存策略。以下的步骤基于硬盘策略为DiskCacheStrategy.ALL,即缓存解码后的图片,也缓存原始图片。　二:先调用DecodeJob的run方法,进而调用runWrapped方法,根据runReason这个标记,生成不同的解码器。　三:先获取ResourceCaheGenerator,去检查硬盘DiskLruCache中有没有解码后的图片资源,如果没有则拿到下一个解码器DataCacheGenerator,调用其的startNext方法,去检查硬盘DiskLruCache中有没有原始的图片资源。如果还是没有,则最后调用rescgedule方法再次调用DncodeJob的run方法并且更改runReason的值。　四:根据runReason,将SourceGenerator赋值给当前解码器,第一次dataToCache一定为null,所以一定会进行网络请求,去根据URl获取图片资源,然后再回调DecodeJob的run方法　五:同样会走到这一步,这一次因为已经进行过网络的获取,所以dataToCache不为null,即会将图片资源放到硬盘缓存DiskLruCache中,然后再把DataCacheGenerator赋值给SourceGenerator,然后调用SourceGenerator.startNext即DataCacheGenerator的startNext方法。　六:由于此时可以在硬盘中拿到数据了,所以和第三步的执行过程不一样,即会经过一系列步骤会回调到onResourceReady方法将图片显示,并将资源放到弱引用缓存中。　再次结合下面这个图看会更好理解:　Glide　缓存机制　@Nullable　private　EngineResource　loadFromMemory(　EngineKey　key,　boolean　isMemoryCacheable,　long　startTime)　{　if　(!isMemoryCacheable)　{　return　null;　}　//从弱引用对象...　Glide　缓存机制　@Nullableprivate　EngineResource　loadFromMemory(　EngineKey　key,　boolean　isMemoryCacheable,　long　startTime)　{　if　(!isMemoryCacheable)　{　return　null;　}　//从弱引用对象加载　图片加载过二次加载会从弱引用对象加载　EngineResource　active　=　loadFromActiveResources(key);　if　(active　!=　null)　{　if　(VERBOSE_IS_LOGGABLE)　{　logWithTimeAndKey("Loaded　resource　from　active　resources",　startTime,　key);　}　return　active;　}　//退出app,在次进入,弱引用已被清理,从LurCached缓存加载　EngineResource　cached　=　loadFromCache(key);　if　(cached　!=　null)　{　if　(VERBOSE_IS_LOGGABLE)　{　logWithTimeAndKey("Loaded　resource　from　cache",　startTime,　key);　}　return　cached;　}　return　null;}　 Glide　在加载图片前会查询　弱引用中是否有图片,如果有会直接加载,如果没有就会去找　LruCached.　synchronized　(this)　{　//查找缓存　memoryResource　=　loadFromMemory(key,　isMemoryCacheable,　startTime);　if　(memoryResource　==　null)　{　//缓存为空,查找磁盘缓存　return　waitForExistingOrStartNewJob(　glideContext,　model,　signature,　width,　height,　resourceClass,　transcodeClass,　priority,　diskCacheStrategy,　transformations,　isTransformationRequired,　isScaleOnlyOrNoTransform,　options,　isMemoryCacheable,　useUnlimitedSourceExecutorPool,　useAnimationPool,　onlyRetrieveFromCache,　cb,　callbackExecutor,　key,　startTime)Avoid　calling　back　while　holding　the　engine　lock,　doing　so　makes　it　easier　for　callers　to　//　deadlock.　cb.onResourceReady(memoryResource,　DataSource.MEMORY_CACHE);　return　null;　}　如果LruCached　也不存在,会查找磁盘缓存,如果磁盘缓存也没有才会进行网络请求,Glide　网络请求类HttpUrlFetcher 　private　　LoadStatus　waitForExistingOrStartNewJob(　GlideContext　glideContext,　Object　model,　Key　signature,　int　width,　int　height,　Class　resourceClass,　Class　transcodeClass,　Priority　priority,　DiskCacheStrategy　diskCacheStrategy,　Map,　Transformation>　transformations,　boolean　isTransformationRequired,　boolean　isScaleOnlyOrNoTransform,　Options　options,　boolean　isMemoryCacheable,　boolean　useUnlimitedSourceExecutorPool,　boolean　useAnimationPool,　boolean　onlyRetrieveFromCache,　ResourceCallback　cb,　Executor　callbackExecutor,　EngineKey　key,　long　startTime)　{　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　=　engineJobFactory.build(　key,　isMemoryCacheable,　useUnlimitedSourceExecutorPool,　useAnimationPool,　onlyRetrieveFromCache);　DecodeJob　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);　//读磁盘缓存　engineJob.start(decodeJob);　if　(VERBOSE_IS_LOGGABLE)　{　logWithTimeAndKey("Started　new　load",　startTime,　key);　}　return　new　LoadStatus(cb,　engineJob);　}　EngineJob　是一个线程对象,调用 strat　方法开启一个线程池,执行EngineJob线程的run　方法　class　DecodeJob　implements　DataFetcherGenerator.FetcherReadyCallback,　Runnable,　Comparable>,　Poolable　{　public　synchronized　void　start(DecodeJob　decodeJob)　{　this.decodeJob　=　decodeJob;　GlideExecutor　executor　=　decodeJob.willDecodeFromCache()　?　diskCacheExecutor　:　getActiveSourceExecutor();　//线程池　executor.execute(decodeJob);　}　在run　方法中runWapped()方法　-->DecodeJob　@Override　public　void　run(try　{　if　(isCancelled)　{　notifyFailed();　return;　}　runWrapped();　}　catch　(CallbackException　e)　{　}　catch　(Throwable　t)　{　if　(stage　!=　Stage.ENCODE)　{　throwables.add(t);　notifyFailed();　}　}　finally　{　if　(localFetcher　!=　null)　{　localFetcher.cleanup();　}　GlideTrace.endSection(在runWraoped()方法中分为三个swith　分别　INITIALIZE　SWITCH_TO_SOURCE_SERVICE　DECODE_DATA　默认走第一个INITIALIZE　/**　*　读磁盘缓存　*/　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);　}　}　在第一个　INITIALIZE　方法中调用 runGenerators方法 　-->DecodeJob　private　void　runGenerators()　{　currentThread　=　Thread.currentThread();　startFetchTime　=　LogTime.getLogTime();　boolean　isStarted　=　false;　while　(!isCancelled　&&　currentGenerator　!=　null　//currentGenerator.startNext()　&&　!(isStarted　=　currentGenerator.startNext()))　{　stage　=　getNextStage(stage);　currentGenerator　=　getNextGenerator();　if　(stage　==　Stage.SOURCE)　{　reschedule();　return;We've　run　out　of　stages　and　generators,　give　up.　if　((stage　==　Stage.FINISHED　||　isCancelled)　&&　!isStarted)　{　notifyFailed(Otherwise　a　generator　started　a　new　load　and　we　expect　to　be　called　back　in　//　onDataFetcherReady.　}　在runGenerators　方法中调用currentGenerator.startNext()　这个currentGenerator　调的是　ResourceCacheGenerator　startNext　方法　public　boolean　startNext()　{　//添加到LruCache中List　sourceIds　=　helper.getCacheKeys();　if　(sourceIds.isEmpty())　{　return　false;　}　List>　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);　//　PMD.AvoidInstantiatingObjectsInLoops　Each　iteration　is　comparatively　expensive　anyway,　//　we　only　run　until　the　first　one　succeeds,　the　loop　runs　for　only　a　limited　//　number　of　iterations　on　the　order　of　10-20　in　the　worst　case.　//key　currentKey　=　new　ResourceCacheKey(　//　NOPMD　AvoidInstantiatingObjectsInLoops　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　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;　}　//添加到LruCache中　然后在创建存储key　通过　key　找到磁盘存储的文件 然后调用　 loadData.fetcher.loadData(helper.getPriority(),　this); 　-->ByteBufferFileLoader　@Override　public　void　loadData(　@NonNull　Priority　priority,　@NonNull　DataCallback　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);　}　然后调用onDataReady 　-->ResourceCacheGenerator　@Override　public　void　onDataReady(Object　data)　{　cb.onDataFetcherReady(　sourceKey,　data,　loadData.fetcher,　DataSource.RESOURCE_DISK_CACHE,　currentKey);　}　 然后调用　onDataFetcherReady　-->DecodeJob　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(然后调用　 decodeFromRetrievedData(); 　-->DecodeJob　private　void　decodeFromRetrievedData()　{　if　(Log.isLoggable(TAG,　Log.VERBOSE))　{　logWithTimeAndKey(　"Retrieved　data",　startFetchTime,　"data:　"　+　currentData　+　",　cache　key:　"　+　currentSourceKey　+　",　fetcher:　"　+　currentFetcher);　}　Resource　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　Resource　不等于空调用　notifyEncodeAndRelease 　-->DecodeJob　private　void　notifyEncodeAndRelease(Resource　resource,　DataSource　dataSource)　{　if　(resource　instanceof　Initializable)　{　((Initializable)　resource).initialize();　}　Resource　result　=　resource;　LockedResource　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();　}　然后调用　notifyComplete　-->DecodeJob 　private　void　notifyComplete(Resource　resource,　DataSource　dataSource)　{　setNotifiedOrThrow();　callback.onResourceReady(resource,　dataSource);　}　 然后调用　onResourceReady　--> EngineJob　@Override　public　void　onResourceReady(Resource　resource,　DataSource　dataSource)　{　synchronized　(this)　{　this.resource　=　resource;　this.dataSource　=　dataSource;　}　notifyCallbacksOfResult();　}　 然后调用　notifyCallbacksOfResult-　-> EngineJob 　@Synthetic　void　notifyCallbacksOfResult()　{　ResourceCallbacksAndExecutors　copy;　Key　localKey;　EngineResource　localResource;　synchronized　(this)　{　stateVerifier.throwIfRecycled();　if　(isCancelled)　{　//　TODO:　Seems　like　we　might　as　well　put　this　in　the　memory　cache　instead　of　just　recycling　//　it　since　we've　gotten　this　far...　resource.recycle();　release();　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,　key,　resourceListener);　//　Hold　on　to　resource　for　duration　of　our　callbacks　below　so　we　don't　recycle　it　in　the　//　middle　of　notifying　if　it　synchronously　released　by　one　of　the　callbacks.　Acquire　it　under　//　a　lock　here　so　that　any　newly　added　callback　that　executes　before　the　next　locked　section　//　below　can't　recycle　the　resource　before　we　call　the　callbacks.　hasResource　=　true;　copy　=　cbs.copy();　incrementPendingCallbacks(copy.size()　+　1);　localKey　=　key;　localResource　=　engineResource;　}　//保存弱引用　engineJobListener.onEngineJobComplete(this,　localKey,　localResource);　for　(final　ResourceCallbackAndExecutor　entry　:　copy)　{　//CallResourceReady　线程run方法　entry.executor.execute(new　CallResourceReady(entry.cb));　}　decrementPendingCallbacks();　}　@SuppressWarnings("WeakerAccess")　@Synthetic　synchronized　void　incrementPendingCallbacks(int　count)　{　Preconditions.checkArgument(isDone(),　"Not　yet　complete!");　if　(pendingCallbacks.getAndAdd(count)　==　0　&&　engineResource　!=　null)　{　engineResource.acquire();　}　}　executor　线程池调用 CallResourceReady　线程run方法　-->CallResourceReady　private　class　CallResourceReady　implements　Runnable　{　private　final　ResourceCallback　cb;　CallResourceReady(ResourceCallback　cb)　{　this.cb　=　cb;　}　@Override　public　void　run()　{　//　Make　sure　we　always　acquire　the　request　lock,　then　the　EngineJob　lock　to　avoid　deadlock　//　(b/136032534).　synchronized　(cb.getLock())　{　synchronized　(EngineJob.this)　{　if　(cbs.contains(cb))　{　//　Acquire　for　this　particular　callback.　engineResource.acquire();　callCallbackOnResourceReady(cb);　removeCallback(cb);　}　decrementPendingCallbacks(然后调用　callCallbackOnResourceReady -　-> EngineJob 　@SuppressWarnings("WeakerAccess")　@Synthetic　@GuardedBy("this")　void　callCallbackOnResourceReady(ResourceCallback　cb)　{　try　{　//　This　is　overly　broad,　some　Glide　code　is　actually　called　here,　but　it's　much　//　simpler　to　encapsulate　here　than　to　do　so　at　the　actual　call　point　in　the　//　Request　implementation.　cb.onResourceReady(engineResource,　dataSource);　}　catch　(Throwable　t)　{　throw　new　CallbackException(t);　}　}　 然后调用　onResourceReady　-->SingleRequest　@Override　public　void　onResourceReady(Resource　resource,　DataSource　dataSource)　{　stateVerifier.throwIfRecycled();　Resource　toRelease　=　null;　try　{　synchronized　(requestLock)　{　loadStatus　=　null;　if　(resource　==　null)　{　onLoadFailed(exception);　return;　}　Object　received　=　resource.get();　if　(received　==　null　||　!transcodeClass.isAssignableFrom(received.getClass()))　{　toRelease　=　resource;　this.resource　=　null;　onLoadFailed(exception);　return;　}　if　(!canSetResource())　{　toRelease　=　resource;　this.resource　=　null;　//　We　can't　put　the　status　to　complete　before　asking　canSetResource().　status　=　Status.COMPLETE;　return;　}　onResourceReady((Resource)　resource,　(R)　received,　dataSource);　}　}　finally　{　if　(toRelease　!=　null)　{　engine.release(toRelease)然后调用　onResourceReady　-->SingleRequest 　@GuardedBy("requestLock")　private　void　onResourceReady(Resource　resource,　R　result,　DataSource　dataSource)　{　//　We　must　call　isFirstReadyResource　before　setting　status.　boolean　isFirstResource　=　isFirstReadyResource();　status　=　Status.COMPLETE;　this.resource　=　resource;　if　(glideContext.getLogLevel()　<=　Log.DEBUG)　{　}　isCallingCallbacks　=　true;　try　{　boolean　anyListenerHandledUpdatingTarget　=　false;　if　(requestListeners　!=　null)　{　for　(RequestListener　listener　:　requestListeners)　{　anyListenerHandledUpdatingTarget　|=　listener.onResourceReady(result,　model,　target,　dataSource,　isFirstResource);　}　}　anyListenerHandledUpdatingTarget　|=　targetListener　!=　null　&&　targetListener.onResourceReady(result,　model,　target,　dataSource,　isFirstResource);　if　(!anyListenerHandledUpdatingTarget)　{　Transition　animation　=　animationFactory.build(dataSource,　isFirstResource);　target.onResourceReady(result,　animation);　}　}　finally　{　isCallingCallbacks　=　false;　}　notifyLoadSuccess(target　为ImageViewTarget　target.onResourceReady(result,　animation);　-->　ImageViewTarget　@Override　public　void　onResourceReady(@NonNull　Z　resource,　@Nullable　Transition　transition)　{　if　(transition　==　null　||　!transition.transition(resource,　this))　{　setResourceInternal(resource);　}　else　{　maybeUpdateAnimatable(resource);　}　}　然后调用　setResourceInternal　-->　ImageViewTarget　private　void　setResourceInternal(@Nullable　Z　resource)　{　//　Order　matters　here.　Set　the　resource　first　to　make　sure　that　the　Drawable　has　a　valid　and　//　non-null　Callback　before　starting　it.　setResource(resource);　maybeUpdateAnimatable(resource);　}　@Override　protected　void　setResource(@Nullable　Drawable　resource)　{　Log.d(TAG,　"setResource:resource);　view.setImageDrawable(resource);　}　这就是图片加载的整体流程,首先Glide会查询弱引用,如果弱引用没有,会查找LruCached,如果LruCached也没有会查找DiskLruCache　磁盘缓存,如果磁盘缓存也没有,才会进行网络请求,请求到数据会同步到弱引用,LruCached,DiskLruCache,这就是整体策略,这还要注意,如果磁盘缓存有图片,就不会网络请求,会同步到弱引用和LruCache　中.