前面幾片文章主要介紹了下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
源碼。有興趣的同窗能夠關注下。