前面几片文章主要介绍了下Picasso
,相对来讲Picasso
源码看起来会比较轻松,因此若是想研究图片框架的话,建议先从Picasso
下手,这样会比较容易。java
今天只分析最简单的一行代码,后面会慢慢深刻。 虽然只有一行代码,可是里面的整个逻辑确实很是复杂。数组
Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(ivTest)
复制代码
对,这应该也是咱们使用Glide
时候最经常使用的一句代码,下面咱们就一步步跟入。缓存
//------Glide.java------
//with重载方法有不少,这里先讲一个
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
return Glide.get(context).getRequestManagerRetriever();
}
复制代码
第一次触发Glide.get
方法,默认建立一个Glide
对象,以下bash
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) {
isInitializing = true;
initializeGlide(context);
isInitializing = false;
}
private static void initializeGlide(@NonNull Context context) {
initializeGlide(context, new GlideBuilder());
}
//一步步往下看,就到了这里,真正开始建立Glide对象的方法
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
....
//这里代码不少,都省略,直接看最关键的一个方法,build
Glide glide = builder.build(applicationContext);
....
Glide.glide = glide;
}
复制代码
以上是查找的过程的代码,不是特别重要,下面是GlideBuilder的build方法,很是重要。网络
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);
}
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions);
}
复制代码
Glide对象里面存的东西不少,上面初始化了不少重要的东西,先不深刻去看,可是根据名字也能大概的猜到对象的做用。app
大概就这样一个初步的印象,可能不正确,后面能够慢慢验证。 下面继续回到刚才的with的方法。框架
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
return Glide.get(context).getRequestManagerRetriever();
}
复制代码
这里的getRequestManagerRetriever,其实就是build方法中直接new出来的RequestManagerRetriever
ide
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
复制代码
因此咱们再跟进去看下RequestManagerRetriever
的get
方法函数
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
...
@NonNull
private RequestManager supportFragmentGet( @NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
//建立一个SupportRequestManagerFragment,来获取生命周期的状态,来对图片进行管理(这个后面再深刻,这里能够简单理解为,就是为了利用Fragment的生命周期)
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
//刚开始建立的SupportRequestManagerFragment的requestManager==null
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
复制代码
get
方法有不少重载,这里咱们就以参数为FragmentActivity
为例子。 get
方法主要是为了建立RequestManager
.工具
回过头再看Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(ivTest)
, 接下来就是调用了RequestManager
对象的load
方法
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
...
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
...
//调用了as方法,其实主要就是建立一个RequestBuilder对象,而后传入最终要转换成的资源类型,显然默认是转换为Drawable.class
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as( @NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
...
@NonNull
@Override
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
...
//调用load方法传入url地址时,并无真正的去发生请求获取到图片,只是设置了一个参数
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
复制代码
这里的代码其实比较简单,没有什么好介绍的,简单的说就是使用了建造者模式,而后建立了一个新的对象RequestBuilder
,而后传入一些参数。既然是建造者模式,那么最后RequestBuilder
确定会生成一个Request
。
接下来再回头看
Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(ivTest)
复制代码
下面就应该是调用RequestBuilder
的into
方法了
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
...
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions);
}
...
private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, @NonNull RequestOptions options) {
...
Request request = buildRequest(target, targetListener, options);
//获取到当前target绑定的request请求,若是如今正在运行的这个请求跟这个target以前绑定的请求是同样的话,
//就判断下以前的请求是否有再运行,没有运行就开始运行,有运行就不操做。而且回收当前要运行的Request对象
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跟request绑定
target.setRequest(request);
//这里才是正在发起请求的地方
requestManager.track(target, request);
return target;
}
复制代码
into方法中有2句比较关键的地方,这里提取出来单独来说。
1. Request request = buildRequest(target, targetListener, options);
2. requestManager.track(target, request);
复制代码
先看1,在RequestBuilder
中调用buildRequest,构建一个Request
对象
private Request buildRequest( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, RequestOptions requestOptions) {
return buildRequestRecursive(
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions);
...
private Request buildRequestRecursive( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, @Nullable RequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight, RequestOptions requestOptions) {
...
Request mainRequest =
buildThumbnailRequestRecursive(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions);
...
return errorRequestCoordinator;
}
...
//顾名思义,建立一个缩略图的Request,先判断是否有设置缩放的一些熟悉
//若是没有,就获取一个没有缩放的Request
private Request buildThumbnailRequestRecursive( Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, @Nullable RequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight, RequestOptions requestOptions) {
if (thumbnailBuilder != null) {
...
} else if (thumbSizeMultiplier != null) {
...
Request thumbnailRequest =
obtainRequest(
target,
targetListener,
thumbnailOptions,
coordinator,
transitionOptions,
getThumbnailPriority(priority),
overrideWidth,
overrideHeight);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
return obtainRequest(
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight);
}
}
//绕了半天,这里才是真正建立一个Request的地方
private Request obtainRequest( Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, RequestOptions requestOptions, RequestCoordinator requestCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight) {
return SingleRequest.obtain(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory());
}
复制代码
看一些优秀的三方源码,老是这样,方法重载不少,方法参数不少,很容易晕,你们要一步步往里面跟,总能看懂的。
这里咱们最后找到的是建立了一个SingleRequest
对象。固然若是说你在 Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(ivTest)
设置了一些宽高,或者是缩放的属性,那么走的分支可能就不是这个。后面咱们再分析。先从最简单的分支入手,一步步解析。
接下来咱们继续看第2句关键的代码
requestManager.track(target, request);
复制代码
void track(@NonNull Target<?> target, @NonNull Request request) {
...
requestTracker.runRequest(request);
}
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
//正常状况isPaused=false,走这个分支,开始请求
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
...
public void begin() {
...
status = Status.WAITING_FOR_SIZE;
//这里先判断overrideWidth,overrideHeight是否合法
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());
}
...
}
复制代码
咱们这里直接看到begin方法
private static boolean isValidDimension(int dimen) {
return dimen > 0 || dimen == Target.SIZE_ORIGINAL;
}
复制代码
因为咱们并无设置宽高,因此返回false,走下面分支
target.getSize(this);
public void getSize(@NonNull SizeReadyCallback cb) {
sizeDeterminer.getSize(cb);
}
void getSize(@NonNull SizeReadyCallback cb) {
int currentWidth = getTargetWidth();
int currentHeight = getTargetHeight();
if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
cb.onSizeReady(currentWidth, currentHeight);
return;
}
if (!cbs.contains(cb)) {
cbs.add(cb);
}
if (layoutListener == null) {
ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
observer.addOnPreDrawListener(layoutListener);
}
}
复制代码
这里比较关键的就是target.getSize(this);
方法中的参数this
,这里的this
是一个SizeReadyCallback
. 而SingleRequest
实现了SizeReadyCallback
这里就是等待layout布局后,ImageView
有了width
和height后
就会进入SingleRequest
的onSizeReady
回调方法。
主要的经过
ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
observer.addOnPreDrawListener(layoutListener);
复制代码
这3句来监听ImageView
的布局以后的一个回调,也就是有了width
和height
以后的回调。
若是咱们自己设置了缩放,或者是宽高属性,那么Glide就会直接使用width
和height
看成参数,调用 onSizeReady
.下面咱们直接看。
public void onSizeReady(int width, int height) {
...
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
...
loadStatus = engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this);
...
if (status != Status.RUNNING) {
loadStatus = null;
}
...
}
复制代码
这里比较关键的地方
第1点就不说了,直接看上面代码就好。 直接看第2点engine.load
咱们首先看下engine
这个对象是在哪里初始化的。
private Request obtainRequest( Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, RequestOptions requestOptions, RequestCoordinator requestCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight) {
return SingleRequest.obtain(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory());
}
复制代码
能够看出来是前面构建SingleRequest
对象的时候glideContext.getEngine()
传入的一个参数。
glideContext =
new GlideContext(
context,
arrayPool,
registry,
imageViewTargetFactory,
defaultRequestOptions,
defaultTransitionOptions,
engine,
logLevel);
复制代码
而glideContext中的engine
也是参数传入的。 最终找到
@NonNull
Glide build(@NonNull Context context) {
...
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}
...
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions);
}
复制代码
是在建立Glide的时候new出来的一个Engine
,不本身传入的话,会默认构建一个。而后供后面使用。 下面咱们继续看Engine.load
方法
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, boolean isScaleOnlyOrNoTransform, Options options, boolean isMemoryCacheable, boolean useUnlimitedSourceExecutorPool, boolean useAnimationPool, boolean onlyRetrieveFromCache, ResourceCallback cb) {
...
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);
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(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);
...
return new LoadStatus(cb, engineJob);
}
复制代码
代码不少,咱们就看重点几个地方。 先经过参数,生成key,经过key,去获取缓存数据,若是有缓存就直接调用SingleRequest
的onResourceReady
方法。
//生成key,其实能够理解为就是一个字符串,而后key-value,获取到对应的缓存
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//而后调用
loadFromActiveResources
//而后调用
loadFromCache
复制代码
若是缓存中都没有数据,那么就继续下面
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
复制代码
先从jobs里面经过key获取前面已经加入的EngineJob。若是有,就直接current.addCallback(cb);
。 意思就是说,前面若是已经执行过一个任务了,就会把任务添加到jobs
,若是后面遇到相同的任务了,就直接在jobs里面获取,能够把jobs就认为是一个HashMap,根据key
来保存。
若是说,是第一次运行任务,也就是加载图片,那么current==null,继续往下走。
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);
engineJob.start(decodeJob);
...
return new LoadStatus(cb, engineJob);
复制代码
建立2个对象,EngineJob和DecodeJob。 jobs.put(key, engineJob);
这里是为了后面若是是加载相同的图片的话,这里会直接获取到EngineJob
而后去处理,而不是每次都新建一个。
接下来继续engineJob.start(decodeJob);
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
...
boolean willDecodeFromCache() {
Stage firstStage = getNextStage(Stage.INITIALIZE);
return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}
复制代码
这里判断了下是使用diskCacheExecutor
仍是getActiveSourceExecutor()
, 其实第一次看源码的时候,咱们能够先来走一遍完整的流程,这2者具体的区别咱们先不要太在乎。
这2者其实都是一个ExecutorService
,是用来处理线程的。
那咱们继续。
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, Runnable, Comparable<DecodeJob<?>>, Poolable 复制代码
DecodeJob实现了Runnable接口 这里调用
executor.execute(decodeJob);
复制代码
其实就是在线程池中找一个线程来执行decodeJob中的run方法。
@Override
public void run() {
...
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (Throwable t) {
...
}
}
//经过状态来获取不一样的生成器,来生成资源
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 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);
}
}
复制代码
上面最重要的方法就是runWrappeed
。 主要3点。
咱们先来看第一点,也就是getNextStage
方法,经过当前状态,来获取后面的一个状态。其实很简单。 状态的顺序就是
INITIALIZE(初始化)-> RESOURCE_CACHE(获取内存缓存)-> DATA_CACHE(获取磁盘缓存)-> SOURCE(真正去请求资源)-> FINISHED(完成)
复制代码
正常状况下,就会按这样步骤一个个来,可是有些时候咱们会设置不缓存的一些参数,那么就会跳过某个步骤。
在代码中也有体现
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
复制代码
初始化后应该是从获取资源缓存,可是diskCacheStrategy.decodeCachedResource()
返回false
的话,那么就直接获取getNextStage(Stage.RESOURCE_CACHE)
,也就是资源缓存的下一个状态。
DiskCacheStrategy
表明缓存的策略,一共有
咱们这里来看下DiskCacheStrategy.NONE
public static final DiskCacheStrategy NONE = new DiskCacheStrategy() {
public boolean isDataCacheable(DataSource dataSource) {
return false;
}
public boolean isResourceCacheable(boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
return false;
}
public boolean decodeCachedResource() {
return false;
}
public boolean decodeCachedData() {
return false;
}
};
复制代码
这里就都返回false。不容许获取缓存数据。
下面来看第2点,获取Generator
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);
}
}
复制代码
经过不一样的stage获取到不一样的Generator
。一开始获取到ResourceCacheGenerator
。
下面看第3点,runGenerators
private void runGenerators() {
...
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
}
复制代码
这里代码很简单,取消的状况先不考虑,主要是这句代码
!(isStarted = currentGenerator.startNext())
复制代码
Generator
中注册了不少ModelLoader<File, ?>
,ModelLoader<File, ?>
能够生成对应的处理资源的LoadData
, 不一样的LoadData
只能加载本身能加载到的资源。
public boolean startNext() {
...
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;
}
复制代码
最终调用的是LoadData
的fetcher
的loadData方法。 这里的fetcher
是HttpUrlFetcher
(为何是这个后面能够再深刻讲,先走完整个流程)。
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
...
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
...
}
复制代码
loadDataWithRedirects
这个方法就不深刻介绍了,使用了HttpURLConnection
去请求资源。 请求完成后,调用了onDataReady
方法,把结果往上传。
这里咱们就要一步步往上找到回调方法。
首先刚才在SourceGenerator
调用的
loadData.fetcher.loadData(helper.getPriority(), this);
复制代码
会发现,参数 DataCallback就是SourceGenerator
。
因此回调的实际上是SourceGenerator
的onDataReady
方法
@Override
public void onDataReady(Object data) {
...
dataToCache = data;
cb.reschedule();
...
}
复制代码
这里又有一个cb也就是Callback
,继续往前找,发现是DecodeJob
, 因此这里又调用了,DecodeJob.reschedule();
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
复制代码
DecodeJob
中又调用了callback.reschedule
,其实这里的callback
是EngineJob
。不少优秀的三方库就是这样,绕来绕去的,看起来比较费劲。
@Override
public void reschedule(DecodeJob<?> job) {
getActiveSourceExecutor().execute(job);
}
复制代码
这里会发现一个很奇怪的东西,由于在前面咱们已经介绍过了,入口就是执行DecodeJob
的run
方法,而后执行完成以后一步步回调,这里居然又去执行DecodeJob
的run
,死循环么,固然不是,咱们继续往下看。
以后的流程跟前面都同样,这里就再也不赘述了,而后又到了SourceGenerator
的startNext
方法
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
..
return started;
}
...
private void cacheData(Object dataToCache) {
...
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
}
复制代码
这个时候跟以前就不同了,由于数据请求已经回来了,dataToCache!=null
,而后调用cacheData
方法,把数据缓存起来。 调用cacheData
方法以后,最后建立了一个DataCacheGenerator
。而后调用startNext
方法。
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
Key sourceId = cacheKeys.get(sourceIdIndex);
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
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;
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;
}
复制代码
这里的代码呢,其实跟前面的SourceGenrator
差很少,因为前面已经缓存了数据,因此cacheFile!=null,获取到的modelLoader
实际上是ByteBufferFileLoader
,而后fetcher
是ByteBufferFetcher
,因此
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
...
callback.onLoadFailed(e);
return;
}
callback.onDataReady(result);
}
复制代码
直接加载文件,返回二进制数组,而后调用回调函数。这里的callback
其实就是DataCacheGenerator
,跟前面同样的,就是不停往前面找。仔细点,仍是很简单的。
@Override
public void onDataReady(Object data) {
cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
}
复制代码
这里cb是DecodeJob
。
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
...
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
...
复制代码
又开始了,设置了一下值runReason = RunReason.DECODE_DATA,又调用了callback
也就是EngineJob
的reschedule
方法。
这里我就不继续往前找了,最后仍是调用了DecodeJob
的run
方法
public void run() {
...
runWrapped();
...
}
private void runWrapped() {
switch (runReason) {
...
case DECODE_DATA:
decodeFromRetrievedData();
break;
...
}
}
private void decodeFromRetrievedData() {
...
Resource<R> resource = null;
try {
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
...
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
....
notifyComplete(result, dataSource);
...
}
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
...
callback.onResourceReady(resource, dataSource);
}
复制代码
这里就比较简单了,获取到资源而后解码后,调用callback也就是EngineJob
的onResourceReady
方法
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
...
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
public boolean handleMessage(Message message) {
...
switch (message.what) {
case MSG_COMPLETE:
job.handleResultOnMainThread();
...
}
void handleResultOnMainThread() {
...
cb.onResourceReady(engineResource, dataSource);
...
}
复制代码
这里的cb其实就是SingleRequest
了。
public void onResourceReady(Resource<?> resource, DataSource dataSource) {
...
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
...
target.onResourceReady(result, animation);
...
}
复制代码
这里的target
其实就是ImageViewTarget
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
...
setResourceInternal(resource);
...
}
private void setResourceInternal(@Nullable Z resource) {
...
setResource(resource);
...
}
protected abstract void setResource(@Nullable Z resource);
复制代码
能够看出setResource
是一个抽象方法。 因为以前传入的是Drawable.class
因此这里的实现是DrawableImageViewTarget
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
复制代码
这里的view其实就是咱们的ImageView
到这里,最简单的Glide加载网络图片的流程已经走完。
若是对整个流程不懂的同窗,实际上是能够debug一下,而后一步一步跟进去。可是因为流程跳来跳去的,可能断点不是很好打。 你们能够先看下个人整个流程,了解大概以后就能够本身打断点了。
后续还会继续深刻Glide
源码。有兴趣的同窗能够关注下。