- Starts tracking the given request.
*/
public void runRequest(Request request) {
requests.add(request); //添加内存缓存
if (!isPaused) {
request.begin(); // 开始
} else {
pendingRequests.add(request); // 挂起请求
}
} 
继续看一下SingleRequest中的begin方法:
@Override
 public void begin() {
 stateVerifier.throwIfRecycled();
 startTime = LogTime.getLogTime();
 // 如果model空的,那么是不能执行的。 这里的model就是前面提到的RequestBuilder中的model
 if (model == null) {
 if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
 width = overrideWidth;
 height = overrideHeight;
 }
 // Only log at more verbose log levels if the user has set a fallback drawable, because
 // fallback Drawables indicate the user expects null models occasionally.
 int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
 onLoadFailed(new GlideException(“Received null model”), logLevel);
 return;
 }
status = Status.WAITING_FOR_SIZE;
 // 如果当前的View尺寸已经加载获取到了,那么就会进入真正的加载流程。
 if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
 onSizeReady(overrideWidth, overrideHeight);
 } else {
 // 反之,当前View还没有画出来,那么是没有尺寸的。
 // 这里会调用到ViewTreeObserver.addOnPreDrawListener。
 // 等待View的尺寸都ok,才会继续
 target.getSize(this);
 }
// 如果等待和正在执行状态,那么当前会加载占位符Drawable
 if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
 && canNotifyStatusChanged()) {
 target.onLoadStarted(getPlaceholderDrawable());
 }
 if (Log.isLoggable(TAG, Log.VERBOSE)) {
 logV("finished run method in " + LogTime.getElapsedMillis(startTime));
 }
 }
接下来是target.getSize(this)方法。这里主要说一下尺寸未加载出来的情况(ViewTarget.java):
void getSize(SizeReadyCallback cb) {
 int currentWidth = getViewWidthOrParam();
 int currentHeight = getViewHeightOrParam();
 if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) {
 cb.onSizeReady(currentWidth, currentHeight);
 } else {
 // We want to notify callbacks in the order they were added and we only expect one or two
 // callbacks to
 // be added a time, so a List is a reasonable choice.
 if (!cbs.contains(cb)) {
 cbs.add(cb);
 }
 if (layoutListener == null) {
 final ViewTreeObserver observer = view.getViewTreeObserver();
 layoutListener = new SizeDeterminerLayoutListener(this);
 // 绘画之前加入尺寸的监听。这一点我想大部分Android开发同学应该都知道。
 // 接下来在看看系统触发该Listener时target又干了些什么。
 observer.addOnPreDrawListener(layoutListener);
 }
 }
 }
private static class SizeDeterminerLayoutListener implements ViewTreeObserver
 .OnPreDrawListener {
 // 注意这里是弱引用
 private final WeakReference sizeDeterminerRef;
public SizeDeterminerLayoutListener(SizeDeterminer sizeDeterminer) {
 sizeDeterminerRef = new WeakReference<>(sizeDeterminer);
 }
@Override
 public boolean onPreDraw() {
 if (Log.isLoggable(TAG, Log.VERBOSE)) {
 Log.v(TAG, “OnGlobalLayoutListener called listener=” + this);
 }
 SizeDeterminer sizeDeterminer = sizeDeterminerRef.get();
 if (sizeDeterminer != null) {
 // 通知SizeDeterminer去重新检查尺寸,并触发后续操作。
 // SizeDeterminer有点像工具类,又作为尺寸回调的检测接口
 sizeDeterminer.checkCurrentDimens();
 }
 return true;
 }
 }
ok,继续回到SingleRequest.onSizeReady方法,主要就是Engine发起load操作
public void onSizeReady(int width, int height) {
 stateVerifier.throwIfRecycled();
 if (Log.isLoggable(TAG, Log.VERBOSE)) {
 logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
 }
 if (status != Status.WAITING_FOR_SIZE) {
 return;
 }
 status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
 this.width = Math.round(sizeMultiplier * width);
 this.height = Math.round(sizeMultiplier * height);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
 logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
 }
 loadStatus = engine.load(
 glideContext,
 model,
 requestOptions.getSignature(),
 this.width,
 this.height,
 requestOptions.getResourceClass(),
 transcodeClass,
 priority,
 requestOptions.getDiskCacheStrategy(),
 requestOptions.getTransformations(),
 requestOptions.isTransformationRequired(),
 requestOptions.getOptions(),
 requestOptions.isMemoryCacheable(),
 this);
 if (Log.isLoggable(TAG, Log.VERBOSE)) {
 logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
 }
 }
特别的,所有的操作都是来之唯一一个Engine,它的创建是来至于Glide的初始化。如果有需要修改缓存配置的同学可以继续看一下diskCacheFactory的创建:
if (engine == null) {
 engine = new Engine(memoryCache, diskCacheFactory, diskCacheExecutor, sourceExecutor);
 }
继续看一下Engine.load的详细过程:
public LoadStatus load(
 GlideContext glideContext,
 Object model,
 Key signature,
 int width,
 int height,
 Class<?> resourceClass,
 Class transcodeClass,
 Priority priority,
 DiskCacheStrategy diskCacheStrategy,
 Map<Class<?>, Transformation<?>> transformations,
 boolean isTransformationRequired,
 Options options,
 boolean isMemoryCacheable,
 ResourceCallback cb) {
 Util.assertMainThread();
 long startTime = LogTime.getLogTime();
// 创建key,这是给每次加载资源的唯一标示。
 EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
 resourceClass, transcodeClass, options);
// 通过key查找缓存资源 (PS 这里的缓存主要是内存中的缓存,切记,可以查看MemoryCache)
 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;
 }
// 这是一个二级内存的缓存引用,很简单用了一个Map<Key, WeakReference<EngineResource<?>>>装载起来的。
 // 这个缓存主要是谁来放进去呢? 可以参考上面一级内存缓存loadFromCache方法。
 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;
 }
// 根据key获取缓存的job。
 EngineJob current = jobs.get(key);
 if (current != null) {
 current.addCallback(cb); // 给当前job添加上回调Callback
 if (Log.isLoggable(TAG, Log.VERBOSE)) {
 logWithTimeAndKey(“Added to existing load”, startTime, key);
 }
 return new LoadStatus(cb, current);
 }
// 创建job
 EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
 DecodeJob decodeJob = decodeJobFactory.build(
 glideContext,
 model,
 key,
 signature,
 width,
 height,
 resourceClass,
 transcodeClass,
 priority,
 diskCacheStrategy,
 transformations,
 isTransformationRequired,
 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);
 }
上面有一些值得注意的地方:
下面来看看DecodeJob是如何执行的:
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);
 }
 }
// 这里的阶段策略首先是从resource中寻找,然后再是data,,再是source
 private Stage getNextStage(Stage current) {
 switch (current) {
 case INITIALIZE:
 // 根据定义的缓存策略来回去下一个状态
 // 缓存策略来之于RequestBuilder的requestOptions域
 // 如果你有自定义的策略,可以调用RequestBuilder.apply方法即可
 // 详细的可用缓存策略请参看DiskCacheStrategy.java
 return diskCacheStrategy.decodeCachedResource()
 ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
 case RESOURCE_CACHE:
 return diskCacheStrategy.decodeCachedData()
 ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
 case DATA_CACHE:
 return Stage.SOURCE;
 case SOURCE:
 case FINISHED:
 return Stage.FINISHED;
 default:
 throw new IllegalArgumentException("Unrecognized stage: " + current);
 }
// 根据Stage找到数据抓取生成器。
 private DataFetcherGenerator getNextGenerator() {
 switch (stage) {
 case RESOURCE_CACHE:
 // 产生含有降低采样/转换资源数据缓存文件的DataFetcher。
 return new ResourceCacheGenerator(decodeHelper, this);
 case DATA_CACHE:
 // 产生包含原始未修改的源数据缓存文件的DataFetcher。
 return new DataCacheGenerator(decodeHelper, this);
 case SOURCE:
 // 生成使用注册的ModelLoader和加载时提供的Model获取源数据规定的DataFetcher。
 // 根据不同的磁盘缓存策略,源数据可首先被写入到磁盘,然后从缓存文件中加载,而不是直接返回。
 return new SourceGenerator(decodeHelper, this);
 case FINISHED:
 return null;
 default:
 throw new IllegalStateException("Unrecognized stage: " + stage);
 }
 }
经过很多流程,最后来到了发起实际请求的地方SourceGenerator.startNext()方法:
public boolean startNext() {
 if (dataToCache != null) {
 Object data = dataToCache;
 dataToCache = null;
 cacheData(data);
 }
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
 return true;
 }
 sourceCacheGenerator = null;
loadData = null;
 boolean started = false;
 // 查找ModelLoader
 while (!started && hasNextModelLoader()) {
 loadData = helper.getLoadData().get(loadDataListIndex++);
 if (loadData != null
 && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
 || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
 started = true;
 根据model的fetcher加载数据
 loadData.fetcher.loadData(helper.getPriority(), this);
 }
 }
 return started;
 }
这里的Model必须是实现了GlideModule接口的,fetcher是实现了DataFetcher接口。有兴趣同学可以继续看一下integration中的okhttp和volley工程。Glide主要采用了这两种网络libray来下载图片。
4.2.2 数据下载完成后的缓存处理SourceGenerator.onDataReady
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);
 }
 }
有些小伙伴可能看不太明白为什么就一个dataToCache = data就完了…其实cb.reschedule()很重要,这里的cb就是DecodeJob.reschedule():
public void reschedule() {
 runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
 callback.reschedule(this);
 }
这里又有一个Callback,继续追踪,这里的Callback接口是定义在DecodeJob内的,而实现是在外部的Engine中(这里会用线程池重新启动当前job,那为什么要这样做呢?源码中的解释是为了不同线程的切换,因为下载都是借用第三方网络库,而实际的编解码是在Glide自定义的线程池中进行的):
public void reschedule(DecodeJob<?> job) {
 if (isCancelled) {
 MAIN_THREAD_HANDLER.obtainMessage(MSG_CANCELLED, this).sendToTarget();
 } else {
 sourceExecutor.execute(job);
 }
 }
接下来继续DecodeJob.runWrapped()方法。这个时候的runReason是SWITCH_TO_SOURCE_SERVICE,因此直接执行runGenerators(),这里继续执行SourceGenerator.startNext()方法,值得注意的dataToCache域,因为上一次执行的时候是下载,因此再次执行的时候内存缓存已经存在,因此直接缓存数据cacheData(data):
private void cacheData(Object dataToCache) {
 long startTime = LogTime.getLogTime();
 try {
 // 根据不同的数据获取注册的不同Encoder
 Encoder encoder = helper.getSourceEncoder(dataToCache);
 DataCacheWriter writer =
 new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
 originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
 // 这里的DiskCache实现是Engine中LazyDiskCacheProvider提供的DiskCacheAdapter。
 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();
} 
// 创建针对缓存的Generator
 sourceCacheGenerator =
 new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
 }
继续回到SourceGenerator.startNext()方法,这个时候已经有了sourceCacheGenerator,那么直接执行DataCacheGenerator.startNext()方法:
public boolean startNext() {
 while (modelLoaders == null || !hasNextModelLoader()) {
 sourceIdIndex++;
 if (sourceIdIndex >= cacheKeys.size()) {
 return false;
 }
Key sourceId = cacheKeys.get(sourceIdIndex);
 Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
 cacheFile = helper.getDiskCache().get(originalKey);
 if (cacheFile != null) {
 this.sourceKey = sourceId;
 modelLoaders = helper.getModelLoaders(cacheFile);
 modelLoaderIndex = 0;
 }
 }
loadData = null;
 boolean started = false;
 // 这里会通过model寻找注册过的ModelLoader
 while (!started && hasNextModelLoader()) {
 ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
 loadData =
 modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
 helper.getOptions());
 // 通过FileLoader继续加载数据
 if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
 started = true;
 loadData.fetcher.loadData(helper.getPriority(), this);
 }
 }
 return started;
 }
这里的ModelLoader跟之前提到过的Register的模块加载器(ModelLoader)对应是modelLoaderRegistry域,具体执行的操作是Registry.getModelLoaders(…)方法如下:
public List<ModelLoader<Model, ?>> getModelLoaders(Model model) {
 List<ModelLoader<Model, ?>> result = modelLoaderRegistry.getModelLoaders(model);
 if (result.isEmpty()) {
 throw new NoModelLoaderAvailableException(model);
 }
 return result;
 }
继续回到DataCacheGenerator.startNext()方法,找到了ModelLoader,这里笔者跟踪到的是FileLoader类(FileFetcher.loadData(…)方法):
public void loadData(Priority priority, DataCallback<? super Data> callback) {
 // 读取文件数据
 try {
 data = opener.open(file);
 } catch (FileNotFoundException e) {
 if (Log.isLoggable(TAG, Log.DEBUG)) {
 Log.d(TAG, “Failed to open file”, e);
 }
 //失败
 callback.onLoadFailed(e);
 return;
 }
 // 成功
 callback.onDataReady(data);
 }
4.2.3 装载流程
 回调通知这里就不打算多讲了,主要线路如下:
–>DataCacheGenerator.onDataReady
 –>SourceGenerator.onDataFetcherReady
 –>DecodeJob.onDataFetcherReady
 –>DecodeJob.decodeFromRetrievedData
 –>DecodeJob.notifyEncodeAndRelease
 –>DecodeJob.notifyComplete
 –>EngineJob.onResourceReady
Debug流程图:
 
需要说明的就是在EngineJob中有一个Handler叫MAIN_THREAD_HANDLER。为了实现在主UI中装载资源的作用,ok继续上边的流程:
–>EngineJob.handleResultOnMainThread
 –>SingleRequest.onResourceReady
 –>ImageViewTarget.onResourceReady
 –>ImageViewTarget.setResource
 –>ImageView.setImageDrawable/ImageView.setImageBitmap
Debug流程图2:
 
数据的装载过程中有一个很重要的步骤就是decode,这个操作发生在DecodeJob.decodeFromRetrievedData的时候,继续看代码:
- ", cache key: " + currentSourceKey
 
写在最后
由于本文罗列的知识点是根据我自身总结出来的,并且由于本人水平有限,无法全部提及,欢迎大神们能补充~
将来我会对上面的知识点一个一个深入学习,也希望有童鞋跟我一起学习,一起进阶。
提升架构认知不是一蹴而就的,它离不开刻意学习和思考。
**这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家,**梳理了多年的架构经验,筹备近1个月最新录制的,相信这份视频能给你带来不一样的启发、收获。


领取方式:点击这里获取免费架构视频资料
最近还在整理并复习一些Android基础知识点,有问题希望大家够指出,谢谢。
希望读到这的您能转发分享和关注一下我,以后还会更新技术干货,谢谢您的支持!
转发+点赞+关注,第一时间获取最新知识点
**这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家,**梳理了多年的架构经验,筹备近1个月最新录制的,相信这份视频能给你带来不一样的启发、收获。
[外链图片转存中…(img-iqK0zuZr-1644917125533)]
[外链图片转存中…(img-6v1BTp6X-1644917125534)]
领取方式:点击这里获取免费架构视频资料
最近还在整理并复习一些Android基础知识点,有问题希望大家够指出,谢谢。
希望读到这的您能转发分享和关注一下我,以后还会更新技术干货,谢谢您的支持!
转发+点赞+关注,第一时间获取最新知识点
Android架构师之路很漫长,一起共勉吧!










