前言
前面几片文章主要介绍了下Picasso
,相对来说Picasso
源码看起来会比较轻松,所以如果想研究图片框架的话,建议先从Picasso
下手,这样会比较容易。
源码分析
今天只分析最简单的一行代码,后面会慢慢深入。
虽然只有一行代码,但是里面的整个逻辑确实非常复杂。
Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(ivTest)
对,这应该也是我们使用Glide
时候最常用的一句代码,下面我们就一步步跟入。
- with
//------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
对象,如下
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对象里面存的东西很多,上面初始化了很多重要的东西,先不深入去看,但是根据名字也能大概的猜到对象的作用。
- sourceExecutor 获取源数据线程池
- diskCacheExecutor 获取diskcache线程池
- animationExecutor 应该是跟动画有关的线程池
- memorySizeCalculator 应该是个工具类,来计算内存的大小
- connectivityMonitorFactory 应该是连接监听的一个工厂类
- bitmapPool 存放bitmap的池
- arrayPool 存放数组的池
- memoryCache 资源缓存对象
- diskCacheFactory disk cache工厂类
- requestManagerRetriever requestManager训练器
大概就这样一个初步的印象,可能不正确,后面可以慢慢验证。
下面继续回到刚才的with的方法。
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
return Glide.get(context).getRequestManagerRetriever();
}
这里的getRequestManagerRetriever,其实就是build方法中直接new出来的RequestManagerRetriever
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;
}
...
}
这里比较关键的地方
- 状态的切换
- 调用engine.load
第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点。
- 获取当前状态的下一个状态,然后赋值给当前状态
- 获取与当前匹配的Generator
- 运行生成器来获取资源。
我们先来看第一点,也就是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.ALL
- DiskCacheStrategy.NONE
- DiskCacheStrategy.DATA
- DiskCacheStrategy.RESOURCE
- DiskCacheStrategy.AUTOMATIC
我们这里来看下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
源码。有兴趣的同学可以关注下。