Glide.with(this).load(url).into(imageView);
經(jīng)過 Glide.with(xxx).load(xxx) 之后饭于,最終會得到 RequestBuilder<Drawable>蜀踏。因此 Glide.with(Context).into(ImageView)最后一步是調(diào)用 RequestBuilder的into(ImageView)方法。
1掰吕、into(ImageView iv)
@SuppressWarnings({"unused", "WeakerAccess"})
public class RequestBuilder{
//加載資源到ImageView控件中果覆,取消view對應的其他加載,同時釋放已經(jīng)已經(jīng)設置到view的資源
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
//設置BaseRequestOptions(請求配置)
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
//
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
...
default:
// Do nothing.
}
}
//glideContext.buildImageViewTarget(view, transcodeClass)
//會返回一個DrawableImageViewTarget或者BitmapImageViewTarget
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
private <Y extends Target<TranscodeType>> Y into(...) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//構(gòu)建請求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//圖片控件的上一個圖片請求
Request previous = target.getRequest();
//如果本次請求和上一個請求相同畴栖,
//而且本次請求不需要跳過緩存或上次請求還沒完成
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();//釋放本次請求
//如果上次的請求已經(jīng)完成随静,重新執(zhí)行一次
//如果上次的請求失敗,則重新開始
//如果上次請求還在執(zhí)行中吗讶,那讓它繼續(xù)跑
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
requestManager.clear(target);//清除target中舊的請求
target.setRequest(request);//給target綁定新的請求
requestManager.track(target, request);//執(zhí)行請求
return target;
}
//圖片請求不需要內(nèi)存緩存同時圖片控件對應的上一個請求已經(jīng)完成燎猛,則返回true
private boolean isSkipMemoryCacheWithCompletePreviousRequest(
BaseRequestOptions<?> options, Request previous) {
return !options.isMemoryCacheable() && previous.isComplete();
}
}
into()方法返回參數(shù)是ViewTarget,ViewTarget是個抽象類照皆,負責加載Bitmap到View上重绷。
- 配置requestOptions的Scaletype類型。
- 調(diào)用buildRequest方法構(gòu)建Request膜毁,并把Request設置給ViewTarget昭卓。
- 調(diào)用requestManager.track()方法執(zhí)行請求。
2瘟滨、buildRequest() 構(gòu)建請求
這里會涉及到三個request
1候醒、SingleRequest 負責執(zhí)行請求并將結(jié)果反映到 Target 上
2、ErrorRequestCoordinator 負責協(xié)調(diào)圖片請求的Request和請求失敗時的errorRequest
3杂瘸、ThumbnailRequestCoordinator 負責協(xié)調(diào)原圖加載的request和縮略圖加載request
2.1 buildRequestRecursive()
public class RequestBuilder {
//構(gòu)建Request的入口
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
//直接調(diào)用buildRequestRecursive倒淫,遞歸調(diào)用創(chuàng)建Request
return buildRequestRecursive(...);
}
//遞歸調(diào)用,這里會分配一般情況下圖片請求Request和請求失敗的調(diào)用的errorRequest
/**
* @params targetListener 圖片請求回調(diào)败玉,可能是null
* @params transitionOptions 過度動畫配置
* @params priority 請求的優(yōu)先級
* @params overrideWidth 指定圖片加載的寬度
* @params overrideHeight 指定圖片加載的高度
* @params callbackExecutor 線程調(diào)度器
*/
private Request buildRequestRecursive(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,//null
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth, //override(int width, int height)
int overrideHeight,//override(int width, int height)
BaseRequestOptions<?> requestOptions
Executor callbackExecutor) {
/* 如果調(diào)用了error(@Nullable RequestBuilder<TranscodeType> errorBuilder)這個方法敌土,errorBuilder才不為
* 空镜硕,比如
* Glide.with(context)
* .load((Object) null)
* .error(
* Glide.with(context)
* .load(errorModel)
* .listener(requestListener))
* .submit();
*/
//ErrorRequestCoordinator 主要用來協(xié)調(diào)圖片請求的Request和請求失敗時的errorRequest
ErrorRequestCoordinator errorRequestCoordinator = null;
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
//圖片請求的Request,調(diào)用buildThumbnailRequestRecursive
Request mainRequest =
buildThumbnailRequestRecursive(...);
if (errorRequestCoordinator == null) {
return mainRequest;
}
...
//構(gòu)建圖片請求失敗時的調(diào)用的errorRequest
Request errorRequest =
errorBuilder.buildRequestRecursive(...);
//內(nèi)部協(xié)調(diào)mainRequest和errorRequest的調(diào)用流程
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
}
第一步判斷是否調(diào)用了error(@Nullable RequestBuilder<TranscodeType> errorBuilder)這個方法返干,如果有兴枯,則先構(gòu)建ErrorRequestCoordinator,然后調(diào)用buildThumbnailRequestRecursive方法矩欠,最后構(gòu)建errorRequest财剖。
2.2 buildThumbnailRequestRecursive()
//遞歸調(diào)用,這里會分配一般情況下圖片請求Request和縮略圖請求的thumbnailRequest
private Request buildThumbnailRequestRecursive(...) {
if (thumbnailBuilder != null) {
//調(diào)用了thumbnail(@Nullable RequestBuilder<TranscodeType> thumbnailRequest) 方法晚顷,thumbnailBuilder 才不為空
//原圖的請求和縮略圖的請求可以不是同一張圖片峰伙,看調(diào)用者的設置
...
//ThumbnailRequestCoordinator用來協(xié)調(diào)兩個請求疗疟,因為有的請求需要同時加載原圖和縮略圖
//如果原圖已經(jīng)加載完成该默,那么縮略圖不會再加載
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
//原圖的請求
Request fullRequest =
obtainRequest(...);
isThumbnailBuilt = true;
//縮略圖的請求
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(...);
isThumbnailBuilt = false;
//配置fullRequest和thumbRequest,內(nèi)部協(xié)調(diào)兩個請求的調(diào)用
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
}
...
}
buildThumbnailRequestRecursive方法構(gòu)建圖片的請求時策彤,會判斷是否有調(diào)用了thumbnail方法栓袖,如果有,就創(chuàng)建ThumbnailRequestCoordinator店诗, 然后創(chuàng)建原圖請求和縮略圖請求裹刮。
2.3 obtainRequest()
private Request obtainRequest(...) {
//返回SingleRequest的實例,SingleRequest是Request的子類
return SingleRequest.obtain(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
小結(jié):構(gòu)建Request時庞瘸,除了構(gòu)建原圖的Request請求之外捧弃,還會判斷是否需要需要設置errorRequest和thumbnailRequest,然后協(xié)調(diào)后這個幾個請求之間的調(diào)用流程擦囊, 最后返回的是SingleRequest實例违霞。
2.4、requestManager.track(target, request) 執(zhí)行圖片請求
public class RequestManager implements LifecycleListener,
ModelTypes<RequestBuilder<Drawable>> {
private final RequestTracker requestTracker;
//RequestTracker用于記錄所有的Target, 以及發(fā)送生命周期事件
private final TargetTracker targetTracker = new TargetTracker();
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);//添加到TargetTracker的集合中
requestTracker.runRequest(request);執(zhí)行請求
}
}
//用于跟蹤進行中請求瞬场、取消和重啟已完成或已失敗的請求
public class RequestTracker {
//記錄所有的request
private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
//記錄等待執(zhí)行的request
private final List<Request> pendingRequests = new ArrayList<>();
private boolean isPaused;
public void runRequest(@NonNull Request request) {
requests.add(request);
//判斷是否在暫停狀態(tài)
if (!isPaused) {
request.begin();//調(diào)用SingleRequest的begin方法
} else {
request.clear();//調(diào)用SingleRequest的clear方法
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
//暫停狀態(tài)情況下买鸽,先記錄起等待執(zhí)行的request
pendingRequests.add(request);
}
}
}
RequestTracker負責跟蹤進行中請求、取消和重啟已完成或已失敗的請求贯被。
requestManager.track(target, request)就是執(zhí)行圖片請求眼五,調(diào)用SingleRequest的begin方法
3、SingleRequest#begin()
public final class SingleRequest<R> implements Request,
SizeReadyCallback,
ResourceCallback,
FactoryPools.Poolable {
//Engine類主要負責啟動下載和管理緩存中的和活躍未回收的資源
private Engine engine;
private Resource<R> resource;
private final StateVerifier stateVerifier = StateVerifier.newInstance();
@Override
public synchronized void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
...
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
//如果已經(jīng)下載完成彤灶,直接回調(diào)onResourceReady看幼,代表加載成功
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
//即未完成也不在運行中的請求,可以當做是新的請求幌陕,從頭開始
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 如果使用了 override() API 為圖片指定了一個固定的寬高
onSizeReady(overrideWidth, overrideHeight);
} else {
// 沒有指定則調(diào)用 target.getSize()
// target.getSize() 方法的內(nèi)部會根據(jù) ImageView 的
// layout_width 和 layout_height 值做一系列的計算诵姜,來算出圖片應該的寬高
// 計算完之后,它也會調(diào)用 onSizeReady() 方法
target.getSize(this);
}
//如果是運行中苞轿,或者還在imageView控件的尺寸時
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
//回調(diào)onLoadStarted的方法茅诱,把placeholder()中設置的圖片設置給view
target.onLoadStarted(getPlaceholderDrawable());
}
...
}
SingleRequest的begin方法中逗物,會進行多個判斷,
- status為COMPLETE就這直接回調(diào)onResourceReady方法瑟俭,
- status為running就拋出異常翎卓,
- status為WAITING_FOR_SIZE,判斷是否調(diào)用override方法設置指定寬高摆寄,如果指定好了寬高值失暴,直接調(diào)用onSizeReady方法;如果沒有微饥,調(diào)用target的getSize方法獲取控件的寬高逗扒,ViewTarget以及其子類實現(xiàn)了View 的 OnPreDrawListener接口,View 初始化完成后也會調(diào)用 SingleRequest的onSizeReady方法
3.1 onSizeReady()
/*
* begin方法中并不會直接發(fā)起請求欠橘,而是等待 ImageView 初始化完成矩肩;
* 對于 ViewTarget 以及其子類來說,會注冊View 的 OnPreDrawListener 事件肃续,
* 等待 View 初始化完成后就調(diào)用onSizeReady方法黍檩,才會開始加載圖片
*/
@Override
public synchronized void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();//獲取設置的縮放比例,計算圖片請求的寬高
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
//調(diào)用engine的加載方法
loadStatus =
engine.load(...);
...
}
}
onSizeReady方法主要就是engine的load方法始锚。
3.2 engine.load()
Engine類負責啟動下載和管理活動資源刽酱、緩存等等。
/**
*Engine類主要負責啟動下載和管理緩存中的和活躍未回收的資源
*/
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
//ActiveResources內(nèi)部設置了HashMap集合瞧捌,保存EngineKey到EngineResource(圖片資源)的軟引用的映射
private final ActiveResources activeResources;
//內(nèi)部的HashMap集合保存EngineKey到EngineJob的映射
private final Jobs jobs;
/*
* 構(gòu)建EngineJob和DecodeJob, 啟動DecodeJob
*/
public synchronized <R> LoadStatus load(...) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//buildKey方法是根據(jù)圖片請求的相關參數(shù)生成對應的key
//EngineKey 用于緩存下載資源的key棵里,對應著一系列的具體的圖片請求參數(shù),不同的參數(shù)姐呐,相同的請求連接對應的key也不一樣
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//從activeResources中的hashmap集合獲取EngineResource的弱引用殿怜,也就是獲取圖片資源引用
//ActiveResources 是Glide的第一級緩存,表示當前正在活動中的資源
//EngineResource 是Resource接口的實現(xiàn)類皮钠,Resource接口包裝了圖片資源的泛型稳捆,是圖片資源的包裝類
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
//EngineResource的引用,直接回調(diào)SingleRequest的onResourceReady方法
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
//從LruCache緩存中獲取資源
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
//從緩存中獲取到資源麦轰,直接回調(diào)SingleRequest的onResourceReady方法
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
// Jobs 內(nèi)部使用HashMap保存EngineKey到EngineJob的映射
//EngineJob 負責管理下載乔夯,啟動DecodeJob
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
//保存cb和callbackExecutor,后面獲取到資源后款侵,回調(diào)cb的onResourceReady方法
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
///緩存中沒有末荐,則新建一個engineJob
EngineJob<R> engineJob =
engineJobFactory.build(...);
/*
* 新建一個DecodeJob
* 負責從緩存或數(shù)據(jù)源中加載原始數(shù)據(jù)并通過解碼器轉(zhuǎn)換為相應的資源類型(Resource)。
* DecodeJob 實現(xiàn)了 Runnable 接口新锈,由 EngineJob 將其運行在指定線程池中
*/
DecodeJob<R> decodeJob =
decodeJobFactory.build(...);
//記錄key和engineJob的映射
jobs.put(key, engineJob);
engineJob.addCallback(cb, callbackExecutor);
//啟動decodeJob
engineJob.start(decodeJob);
...
return new LoadStatus(cb, engineJob);
}
}
- 根據(jù)圖片請求的相關參數(shù)構(gòu)建EngineKey甲脏。
- 從緩存中獲取EngineKey對應的EngineResource對象,如果EngineResource不為空,直接回調(diào)SingleRequest的onResouceReady接口块请,然后返回娜氏;
- 如果換成中沒有EngineKey對應的EngineResource對象,那么查看緩存中是否存在EngineKey對應的EngineJob對象:
(1) 如果有緩存中存在對應的EngineJob對象墩新,說明對應的圖片正在加載中贸弥,添加一個新的ResourceCallback和callbackExecutor到EngineJob中,最后直接返回一個新的LoadStatus海渊。添加了回調(diào)接口后绵疲,圖片資源下載成功后,可以回調(diào)本次添加ResourceCallback的onResourceReady方法臣疑。
(2) 如果緩存中沒有EngineJob盔憨,就新建一個EngineJob和DecodeJob,然后啟動DecodeJob任務讯沈。
4郁岩、engineJob.start(decodeJob)
EngineJob負責管理圖片請求回調(diào),以及圖片下載完成后執(zhí)行回調(diào)芙盘。
DecodeJob負責從磁盤緩存或數(shù)據(jù)源中加載原始數(shù)據(jù)并通過解碼器轉(zhuǎn)換為相應的資源類型驯用。
class EngineJob<R> implements DecodeJob.Callback<R>,
Poolable {
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
//如果是要解碼磁盤的圖片資源脸秽,返回true, GlideExecutor為diskCacheExecutor儒老,否則調(diào)用getActiveSourceExecutor()
//diskCacheExecutor為磁盤緩存加載線程池,不允許用于網(wǎng)絡操作
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
//如果要解密磁盤緩存中的資源返回true, 否則返回false
boolean willDecodeFromCache() {
Stage firstStage = getNextStage(Stage.INITIALIZE);
return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}
//返回三種類型的線程池
//sourceUnlimitedExecutor : 圖片源網(wǎng)絡加載線程池记餐,沒有核心線程數(shù)驮樊, 線程數(shù)無限制
//animationExecutor : 動畫加載線程池
//sourceExecutor : 圖片源網(wǎng)絡加載線程池,有核心線程數(shù)片酝,線程數(shù)有限
private GlideExecutor getActiveSourceExecutor() {
return useUnlimitedSourceGeneratorPool
? sourceUnlimitedExecutor : (useAnimationPool ? animationExecutor : sourceExecutor);
}
}
- GlideExecutor可能為diskCacheExecutor囚衔、sourceUnlimitedExecutor 、animationExecutor 雕沿、sourceExecutor其中一種练湿,把DecodeJob提交給線程池執(zhí)行。
- DecodeJob實現(xiàn)了Runnable接口审轮,EngineJob的start方法就是啟動decodeJob的線程肥哎,執(zhí)行decodeJob的run方法。
4.1 DecodeJob.run()
class DecodeJob<R> {
@Override
public void run() {
...
// Methods in the try statement can invalidate currentFetcher, so set a local variable here to
// ensure that the fetcher is cleaned up either way.
DataFetcher<?> localFetcher = currentFetcher;
if (isCancelled) {
//如果取消加載疾渣,調(diào)用notifyFailed()通知加載資源失敗
notifyFailed();
return;
}
runWrapped();
...
}
//decodeJob初始化時篡诽, runReason被設置為RunReason.INITIALIZE
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//判斷要解碼的數(shù)據(jù)來源,構(gòu)建DataFetcherGenerator實例榴捡,執(zhí)行runGenerators方法
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);
}
}
//getNextStage方法是要確定我們將要解碼的數(shù)據(jù)是來源于哪里的數(shù)據(jù)
//通常判斷順序為INITIALIZE -> RESOURCE_CACHE(圖片轉(zhuǎn)換之后的磁盤緩存) -> DATA_CACHE(原圖的磁盤緩存) -> SOURCE(數(shù)據(jù)源)
private Stage getNextStage(Stage current) {
switch (current) {
//INITIALIZE為Stage的初始狀態(tài)
case INITIALIZE:
// 如果decodeCachedResource() 為 true杈女, 表示嘗試解碼緩存中已經(jīng)被轉(zhuǎn)換的圖片
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
// 如果decodeCachedData() 為 true,表示嘗試解碼磁盤中緩存的原始圖片
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// 如果調(diào)用者選擇只用緩存中檢索資源,則跳過從數(shù)據(jù)源加載
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
//根據(jù)Stage的枚舉值來獲取DataFetcherGenerator, 返回DataFetcherGenerator的子類
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
// 對應被轉(zhuǎn)換的圖片的緩存的 Generator
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
// 對應原始圖片的緩存的 Generator
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
// 對應圖片原始數(shù)據(jù)源的 Generator
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//這里判斷一下喘鸟,之后主要是執(zhí)行currentGenerator.startNext()方法執(zhí)行后續(xù)的邏輯
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
}
Stage是DecodeJob的內(nèi)部枚舉類芋绸,用于表示所要解碼數(shù)據(jù)的來源(內(nèi)存緩存, 磁盤緩存)躏筏,初始化狀態(tài)是INITIALIZE。
- 這里首先是要調(diào)用getNextStage()方法確定需要解碼的數(shù)據(jù)來源呈枉,是緩存的圖片還是原始圖片趁尼;
- 根據(jù)要解碼的數(shù)據(jù)來源,構(gòu)建對應的DataFetcherGenerator派生類(ResourceCacheGenerator猖辫, DataCacheGenerator等)酥泞;DataFetcherGenerator負責構(gòu)建DataFetcher實例, DataFetcher接口負責加載圖片數(shù)據(jù)啃憎。
- 啟動DataFetcherGenerator芝囤,調(diào)用DataFetcherGenerator的startNext()方法,構(gòu)建DataFetcher辛萍。
- 默認情況下悯姊,一開始會調(diào)用ResourceCacheGenerator的startNext()方法,獲取磁盤緩存的數(shù)據(jù)贩毕。
- 如果磁盤沒有緩存到對應的圖片數(shù)據(jù)悯许,要從數(shù)據(jù)源頭加載圖片時(比如從網(wǎng)絡加載圖片),會調(diào)用SourceGenerator的startNext()方法辉阶。
5先壕、 SourceGenerator#startNext()
對應從數(shù)據(jù)源頭加載數(shù)據(jù)的場景,負責構(gòu)建DataFetchers谆甜。
class SourceGenerator implements DataFetcherGenerator,
DataFetcher.DataCallback<Object>,
DataFetcherGenerator.FetcherReadyCallback {
private final DecodeHelper<?> helper;
private volatile ModelLoader.LoadData<?> loadData;
@Override
public boolean startNext() {
...
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//加載數(shù)據(jù)
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
}
- ModelLoader負責將多種復雜的數(shù)據(jù)模式轉(zhuǎn)變成DataFetcher可以加載的的具體資源類型垃僚。
- LoadData是ModelLoader的內(nèi)部類,保存了圖片對應的唯一Key规辱,備用key集合緩存谆棺,以及對應DataFetcher派生類。
- DataFetcher是真正負責加載資源的類罕袋,通過不同的派生類實現(xiàn)來加載不同的數(shù)據(jù)改淑。
當我們加載網(wǎng)絡圖片源數(shù)據(jù)時,loadData.fetcher的實例是HttpUrlFetcher炫贤,即調(diào)用HttpUrlFetcher的loadData方法來加載網(wǎng)絡圖片源數(shù)據(jù)溅固。
5.1 HttpUrlFetcher#loadData()
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super InputStream> callback) {
...
//獲取圖片資源的輸入流
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
//回調(diào)數(shù)據(jù)
callback.onDataReady(result);
...
}
//通過HttpURLConnection加載網(wǎng)絡圖片,返回圖片輸入流
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
Map<String, String> headers) throws IOException {
...
urlConnection = connectionFactory.build(url);
...
urlConnection.connect();
// Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
stream = urlConnection.getInputStream();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (isHttpOk(statusCode)) {
return getStreamForSuccessfulRequest(urlConnection);
}
...
}
HttpUrlFetcher加載網(wǎng)絡圖片數(shù)據(jù)就是通過HttpURLConnection連接url兰珍,獲取圖片輸入流侍郭,然后通過回調(diào)接口把輸入流返回出去。callback.onDataReady()首先會回調(diào)SourceGenerator類的onDataReady()方法。
6亮元、SourceGenerator#onDataReady()
當數(shù)據(jù)獲取成功后猛计,需要執(zhí)行的就是緩存圖片和把圖片設置到圖片控件上了。
//SourceGenerator#onDataReady()
@Override
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;//把inputStream賦值給dataToCache
//cb是SourceGenerator構(gòu)造函數(shù)傳遞進來的爆捞,cb的實例是DecodeJob
cb.reschedule();
}
...
}
//DecodeJob#reschedule
@Override
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
//callback是DecodeJob的init方法傳遞進來的奉瘤,callback的實例是EngineJob
callback.reschedule(this);
}
//EngineJob#reschedule()
@Override
public void reschedule(DecodeJob<?> job) {
//再次把DecodeJob提交到線程池中執(zhí)行,回調(diào)DecodeJob的run方法煮甥。
getActiveSourceExecutor().execute(job);
}
數(shù)據(jù)下載成功后盗温,會經(jīng)過很多的回調(diào)方法,回調(diào)過程為SourceGenerator#onDataReady() --> DecodeJob#reschedule() -> EngineJob#reschedule() --> DecodeJob#run()成肘。
6.1 再次運行DecodeJob線程
//DecodeJob#run
@Override
public void run() {
...
runWrapped();
...
}
private void runWrapped() {
switch (runReason) {
...
case SWITCH_TO_SOURCE_SERVICE:
//runGenerators會再次調(diào)用SourceGenerator的startNext方法
runGenerators();
break;
...
}
//SourceGenerator#startNext()
@Override
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
//把數(shù)據(jù)緩存到磁盤中
cacheData(data);
}
//執(zhí)行了cacheData方法時卖局,會把sourceCacheGenerator重新賦值為DataCacheGenerator。
//執(zhí)行DataCacheGenerator的startNext方法
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
...
}
第二次運行DecodeJob線程双霍,會再次調(diào)用SourceCacheGenerator的startNext方法砚偶,因為在數(shù)據(jù)下載成功的時候,把inputSteam賦值給了dataToCache洒闸,所以startNext方法首先調(diào)用cacheData()方法對數(shù)據(jù)進行磁盤緩存染坯,然后調(diào)用DataCacheGenerator的startNext()方法。
6.2 DataCacheGenerator#startNext()
@Override
public boolean startNext() {
...
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;
// 這里的 fetcher 為 ByteBufferFetcher丘逸,調(diào)用其 loadData() 的時候又會把自身傳遞過去
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
DataCacheGenerator類中单鹿, loadData.fetcher的實例是ByteBufferFetcher對象,loadData.fetcher.loadData就是調(diào)用ByteBufferFetcher的loadData方法鸣个,同時DataCacheGenerator把對象自身作為回調(diào)接口傳遞給ByteBufferFetcher羞反。
//ByteBufferFetcher#loadData()
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
//讀取緩存文件,獲取圖片文件的ByteBuffer數(shù)據(jù)
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
...
callback.onLoadFailed(e);
return;
}
//回調(diào)到DataCacheGenerator的onDataReady方法
callback.onDataReady(result);
}
//DataCacheGenerator#onDataReady()
@Override
public void onDataReady(Object data) {
//cb對象是SourceGenerator囤萤,所以又回調(diào)到SourceGenerator的onDataFetcherReady方法
cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
}
//SourceGenerator#onDataFetcherReady()
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
//SourceGenerator的cb是DecodeJob對象,所以再回調(diào)到DecodeJob的onDataFetcherReady()方法
cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
}
ByteBufferFetcher的loadData方法就是讀取圖片的磁盤緩存轉(zhuǎn)換成ByteBuffer數(shù)據(jù)是趴,然后把數(shù)據(jù)回調(diào)給DecodeJob對象涛舍。
7、解析圖片數(shù)據(jù):DecodeJob#onDataFetcherReady()
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey; //sourceKey是圖片的網(wǎng)絡url地址
this.currentData = data; //data是圖片數(shù)據(jù)唆途,
this.currentFetcher = fetcher; //ByteBufferFetcher
this.currentDataSource = dataSource; //圖片的數(shù)據(jù)來源富雅,為REMOTE,即遠端圖片數(shù)據(jù)源
this.currentAttemptingKey = attemptedKey; //attemptedKey和sourceKey一樣
if (Thread.currentThread() != currentThread) {
...
} else {
try {
// 調(diào)用 decodeFromRetrievedData 解析圖片數(shù)據(jù)
decodeFromRetrievedData();
}
...
}
}
//解析圖片數(shù)據(jù)
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
//currentFetcher為ByteBufferFetcher肛搬,
//currentData為圖片數(shù)據(jù)
//currentDataSource為DATA_DISK_CACHE
//解碼圖片數(shù)據(jù)没佑,轉(zhuǎn)換成Resource類型(LazyBitmapDrawableResource的實例)
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
//把圖片資源回調(diào)出去,然后根據(jù)options參數(shù)温赔,緩存轉(zhuǎn)換的圖片到磁盤中蛤奢。
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
if (resource instanceof Initializable) {
//resource對象為LazyBitmapDrawableResource實例,是BitmapResource的包裝類
//initialize方法是執(zhí)行BitmapResource的initialize方法,執(zhí)行bitmap.prepareToDraw();
((Initializable) resource).initialize();
}
Resource<R> result = resource;
LockedResource<R> lockedResource = null;
if (deferredEncodeManager.hasResourceToEncode()) {
lockedResource = LockedResource.obtain(resource);
result = lockedResource;
}
notifyComplete(result, dataSource);
stage = Stage.ENCODE;
try {
if (deferredEncodeManager.hasResourceToEncode()) {
//根據(jù)options參數(shù)啤贩,緩存轉(zhuǎn)換的圖片到磁盤中
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
//編碼完成待秃,釋放資源
onEncodeComplete();
}
//圖片資源獲取成功,回調(diào)出去
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
//callback為EngineJob的實例對象痹屹,回調(diào)到EngineJob的onResourceReady方法
callback.onResourceReady(resource, dataSource);
}
- onDataFetcherReady首先就是把圖片數(shù)據(jù)解析成Resource圖片包裝類章郁。
- 把圖片資源回調(diào)給EngineJob對象,然后根據(jù)options參數(shù)志衍,緩存轉(zhuǎn)換的圖片到磁盤中暖庄。
7.1 EngineJob#onResourceReady()
//在執(zhí)行engine.load方法中, 代碼current.addCallback(cb, callbackExecutor)把SingleRequest設置給EngineJob對象
synchronized void addCallback(final ResourceCallback cb, Executor callbackExecutor) {
cbs.add(cb, callbackExecutor);
}
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
}
notifyCallbacksOfResult();
}
void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKey;
EngineResource<?> localResource;
synchronized (this) {
...
//把resource包裝成EngineResource
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
copy = cbs.copy();//ResourceCallbacksAndExecutors
localKey = key;
localResource = engineResource;
}
//listener為Engine實例對象楼肪,再回調(diào)到Engine的onEngineJobComplete方法
listener.onEngineJobComplete(this, localKey, localResource);
for (final ResourceCallbackAndExecutor entry : copy) {
//把cb回調(diào)傳遞給CallResourceReady雄驹,并執(zhí)行CallResourceReady線程任務。
entry.executor.execute(new CallResourceReady(entry.cb));
}
}
private class CallResourceReady implements Runnable {
private final ResourceCallback cb;
CallResourceReady(ResourceCallback cb) {
this.cb = cb;
}
@Override
public void run() {
synchronized (EngineJob.this) {
if (cbs.contains(cb)) {
...
callCallbackOnResourceReady(cb);
...
}
}
}
}
synchronized void callCallbackOnResourceReady(ResourceCallback cb) {
try {
//cb為SingleRequest實例對象淹辞,回調(diào)到SingleRequest的onResourceReady方法中
cb.onResourceReady(engineResource, dataSource);
}
...
}
- 先把Resource對象包裝成EngineResource医舆。
- listener.onEngineJobComplete()方法會回調(diào)到Engine#onEngineJobComplete()的方法,把EngineResource對象回調(diào)給Engine象缀。
- entry.executor.execute(new CallResourceReady(entry.cb))啟動CallResourceReady線程蔬将。cb是SingleRequest實例對象,回調(diào)到SingleRequest的onResourceReady方法中央星,并且把EngineResource資源對象傳遞給SingleRequest對象霞怀。
8、Engine#onEngineJobComplete()
對EngineResource執(zhí)行緩存操作莉给。
@Override
public synchronized void onEngineJobComplete(
EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
// A null resource indicates that the load failed, usually due to an exception.
if (resource != null) {
//Engine實現(xiàn)了ResourceListener的接口
//記錄key和ResourceListener接口的實現(xiàn)類(Engine類實例對象)到EngineResource對象中
//當EngineResource的release方法被執(zhí)行時毙石,會回調(diào)ResourceListener的onResourceReleased方法,即回調(diào)到Engine類的onResourceReleased方法中
resource.setResourceListener(key, this);
//把數(shù)據(jù)緩存到activeResources中颓遏,Glide的第一級緩存徐矩,軟引用緩存
if (resource.isCacheable()) {
activeResources.activate(key, resource);
}
}
jobs.removeIfCurrent(key, engineJob);
}
//當EngineResource對象的release方法執(zhí)行時,回調(diào)到此方法
@Override
public synchronized void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
//從第一級緩存中去掉EngineResource對象
activeResources.deactivate(cacheKey);
if (resource.isCacheable()) {
//把EngineResource對象保存到cache叁幢,Glide的第二級緩存滤灯,
//cache對象是LruResourceCache實例對象, LruCache的子類
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
}
}
- 先把EngineKey和Engine設置給EngineResource對象保存起來曼玩。當EngineResource對象被釋放時鳞骤,EngineResource的release方法會回調(diào)Engine的onResourceReleased方法,從一級緩存中刪除EngineResource黍判,然后保存到二級緩存中豫尽。
- 然后把EngineResource保存到Glide的一級緩存activeResources中。
9顷帖、SingleRequest#onResourceReady()
@Override
public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
...
Object received = resource.get();//從EngineResource中獲取BitmapDrawable對象
...
//調(diào)用onResourceReady重載方法
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
...
status = Status.COMPLETE;//設置狀態(tài)為完成狀態(tài)
...
isCallingCallbacks = true;
try {
boolean anyListenerHandledUpdatingTarget = false;
...
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
//target為DrawableImageViewTarget美旧,
//回調(diào)target的onResourceReady方法渤滞,最后會回調(diào)DrawableImageViewTarget的setResource方法
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
//BitmapImageViewTarget#setResource
@Override
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);//給控件設置bitmap圖像
}
SingleRequest的onResourceReady方法會回調(diào)用target的onResourceReady方法,由于target是DrawableImageViewTarget的實例陈症,最終會回調(diào)到BitmapImageViewTarget的setResource方法蔼水,給view設置bitmap資源。
總結(jié): into(imageView)的大體流程如下录肯。
1趴腋、首先構(gòu)建圖片控件的包裝類ViewTarget,實例為DrawableImageViewTarget或者BitmapImageViewTarget论咏。
2优炬、構(gòu)建request,獲取SingleRequest實例對象厅贪,并執(zhí)行reqest.begin方法開始請求蠢护。
3、構(gòu)建EngineJob和DecodeJob养涮,通過EngineJob啟動decodeJob的任務葵硕。
4、構(gòu)建DataFetcher實例贯吓,通過HttpUrlConnection請求圖片網(wǎng)絡url懈凹,獲取圖片輸入流,并把輸入流回調(diào)出去悄谐。
5介评、緩存圖片到磁盤中,繼續(xù)回調(diào)圖片流爬舰。
6们陆、解析圖片數(shù)據(jù),轉(zhuǎn)換成EngineResource圖片包裝類情屹。
7坪仇、緩存圖片到Glide的一級緩存中,并設置后EngineResource釋放時屁商,緩存圖片到二級緩存中烟很。
8、設置圖片資源到圖片控件中蜡镶。