Glide.with(this).load(url).into(imageView);
經過 Glide.with(xxx).load(xxx) 之后,最終會得到 RequestBuilder<Drawable>。因此 Glide.with(Context).into(ImageView)最后一步是調用 RequestBuilder的into(ImageView)方法。
1、into(ImageView iv)
@SuppressWarnings({"unused", "WeakerAccess"})
public class RequestBuilder{
//加載資源到ImageView控件中,取消view對應的其他加載,同時釋放已經已經設置到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()");
}
//構建請求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//圖片控件的上一個圖片請求
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中舊的請求
target.setRequest(request);//給target綁定新的請求
requestManager.track(target, request);//執行請求
return target;
}
//圖片請求不需要內存緩存同時圖片控件對應的上一個請求已經完成,則返回true
private boolean isSkipMemoryCacheWithCompletePreviousRequest(
BaseRequestOptions<?> options, Request previous) {
return !options.isMemoryCacheable() && previous.isComplete();
}
}
into()方法返回參數是ViewTarget,ViewTarget是個抽象類,負責加載Bitmap到View上。
- 配置requestOptions的Scaletype類型。
- 調用buildRequest方法構建Request,并把Request設置給ViewTarget。
- 調用requestManager.track()方法執行請求。
2、buildRequest() 構建請求
這里會涉及到三個request
1、SingleRequest 負責執行請求并將結果反映到 Target 上
2、ErrorRequestCoordinator 負責協調圖片請求的Request和請求失敗時的errorRequest
3、ThumbnailRequestCoordinator 負責協調原圖加載的request和縮略圖加載request
2.1 buildRequestRecursive()
public class RequestBuilder {
//構建Request的入口
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
//直接調用buildRequestRecursive,遞歸調用創建Request
return buildRequestRecursive(...);
}
//遞歸調用,這里會分配一般情況下圖片請求Request和請求失敗的調用的errorRequest
/**
* @params targetListener 圖片請求回調,可能是null
* @params transitionOptions 過度動畫配置
* @params priority 請求的優先級
* @params overrideWidth 指定圖片加載的寬度
* @params overrideHeight 指定圖片加載的高度
* @params callbackExecutor 線程調度器
*/
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) {
/* 如果調用了error(@Nullable RequestBuilder<TranscodeType> errorBuilder)這個方法,errorBuilder才不為
* 空,比如
* Glide.with(context)
* .load((Object) null)
* .error(
* Glide.with(context)
* .load(errorModel)
* .listener(requestListener))
* .submit();
*/
//ErrorRequestCoordinator 主要用來協調圖片請求的Request和請求失敗時的errorRequest
ErrorRequestCoordinator errorRequestCoordinator = null;
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
//圖片請求的Request,調用buildThumbnailRequestRecursive
Request mainRequest =
buildThumbnailRequestRecursive(...);
if (errorRequestCoordinator == null) {
return mainRequest;
}
...
//構建圖片請求失敗時的調用的errorRequest
Request errorRequest =
errorBuilder.buildRequestRecursive(...);
//內部協調mainRequest和errorRequest的調用流程
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
}
第一步判斷是否調用了error(@Nullable RequestBuilder<TranscodeType> errorBuilder)這個方法,如果有,則先構建ErrorRequestCoordinator,然后調用buildThumbnailRequestRecursive方法,最后構建errorRequest。
2.2 buildThumbnailRequestRecursive()
//遞歸調用,這里會分配一般情況下圖片請求Request和縮略圖請求的thumbnailRequest
private Request buildThumbnailRequestRecursive(...) {
if (thumbnailBuilder != null) {
//調用了thumbnail(@Nullable RequestBuilder<TranscodeType> thumbnailRequest) 方法,thumbnailBuilder 才不為空
//原圖的請求和縮略圖的請求可以不是同一張圖片,看調用者的設置
...
//ThumbnailRequestCoordinator用來協調兩個請求,因為有的請求需要同時加載原圖和縮略圖
//如果原圖已經加載完成,那么縮略圖不會再加載
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
//原圖的請求
Request fullRequest =
obtainRequest(...);
isThumbnailBuilt = true;
//縮略圖的請求
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(...);
isThumbnailBuilt = false;
//配置fullRequest和thumbRequest,內部協調兩個請求的調用
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
}
...
}
buildThumbnailRequestRecursive方法構建圖片的請求時,會判斷是否有調用了thumbnail方法,如果有,就創建ThumbnailRequestCoordinator, 然后創建原圖請求和縮略圖請求。
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);
}
小結:構建Request時,除了構建原圖的Request請求之外,還會判斷是否需要需要設置errorRequest和thumbnailRequest,然后協調后這個幾個請求之間的調用流程, 最后返回的是SingleRequest實例。
2.4、requestManager.track(target, request) 執行圖片請求
public class RequestManager implements LifecycleListener,
ModelTypes<RequestBuilder<Drawable>> {
private final RequestTracker requestTracker;
//RequestTracker用于記錄所有的Target, 以及發送生命周期事件
private final TargetTracker targetTracker = new TargetTracker();
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);//添加到TargetTracker的集合中
requestTracker.runRequest(request);執行請求
}
}
//用于跟蹤進行中請求、取消和重啟已完成或已失敗的請求
public class RequestTracker {
//記錄所有的request
private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
//記錄等待執行的request
private final List<Request> pendingRequests = new ArrayList<>();
private boolean isPaused;
public void runRequest(@NonNull Request request) {
requests.add(request);
//判斷是否在暫停狀態
if (!isPaused) {
request.begin();//調用SingleRequest的begin方法
} else {
request.clear();//調用SingleRequest的clear方法
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
//暫停狀態情況下,先記錄起等待執行的request
pendingRequests.add(request);
}
}
}
RequestTracker負責跟蹤進行中請求、取消和重啟已完成或已失敗的請求。
requestManager.track(target, request)就是執行圖片請求,調用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");
}
//如果已經下載完成,直接回調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 {
// 沒有指定則調用 target.getSize()
// target.getSize() 方法的內部會根據 ImageView 的
// layout_width 和 layout_height 值做一系列的計算,來算出圖片應該的寬高
// 計算完之后,它也會調用 onSizeReady() 方法
target.getSize(this);
}
//如果是運行中,或者還在imageView控件的尺寸時
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
//回調onLoadStarted的方法,把placeholder()中設置的圖片設置給view
target.onLoadStarted(getPlaceholderDrawable());
}
...
}
SingleRequest的begin方法中,會進行多個判斷,
- status為COMPLETE就這直接回調onResourceReady方法,
- status為running就拋出異常,
- status為WAITING_FOR_SIZE,判斷是否調用override方法設置指定寬高,如果指定好了寬高值,直接調用onSizeReady方法;如果沒有,調用target的getSize方法獲取控件的寬高,ViewTarget以及其子類實現了View 的 OnPreDrawListener接口,View 初始化完成后也會調用 SingleRequest的onSizeReady方法
3.1 onSizeReady()
/*
* begin方法中并不會直接發起請求,而是等待 ImageView 初始化完成;
* 對于 ViewTarget 以及其子類來說,會注冊View 的 OnPreDrawListener 事件,
* 等待 View 初始化完成后就調用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);
//調用engine的加載方法
loadStatus =
engine.load(...);
...
}
}
onSizeReady方法主要就是engine的load方法。
3.2 engine.load()
Engine類負責啟動下載和管理活動資源、緩存等等。
/**
*Engine類主要負責啟動下載和管理緩存中的和活躍未回收的資源
*/
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
//ActiveResources內部設置了HashMap集合,保存EngineKey到EngineResource(圖片資源)的軟引用的映射
private final ActiveResources activeResources;
//內部的HashMap集合保存EngineKey到EngineJob的映射
private final Jobs jobs;
/*
* 構建EngineJob和DecodeJob, 啟動DecodeJob
*/
public synchronized <R> LoadStatus load(...) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//buildKey方法是根據圖片請求的相關參數生成對應的key
//EngineKey 用于緩存下載資源的key,對應著一系列的具體的圖片請求參數,不同的參數,相同的請求連接對應的key也不一樣
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//從activeResources中的hashmap集合獲取EngineResource的弱引用,也就是獲取圖片資源引用
//ActiveResources 是Glide的第一級緩存,表示當前正在活動中的資源
//EngineResource 是Resource接口的實現類,Resource接口包裝了圖片資源的泛型,是圖片資源的包裝類
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
//EngineResource的引用,直接回調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) {
//從緩存中獲取到資源,直接回調SingleRequest的onResourceReady方法
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
// Jobs 內部使用HashMap保存EngineKey到EngineJob的映射
//EngineJob 負責管理下載,啟動DecodeJob
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
//保存cb和callbackExecutor,后面獲取到資源后,回調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
* 負責從緩存或數據源中加載原始數據并通過解碼器轉換為相應的資源類型(Resource)。
* DecodeJob 實現了 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);
}
}
- 根據圖片請求的相關參數構建EngineKey。
- 從緩存中獲取EngineKey對應的EngineResource對象,如果EngineResource不為空,直接回調SingleRequest的onResouceReady接口,然后返回;
- 如果換成中沒有EngineKey對應的EngineResource對象,那么查看緩存中是否存在EngineKey對應的EngineJob對象:
(1) 如果有緩存中存在對應的EngineJob對象,說明對應的圖片正在加載中,添加一個新的ResourceCallback和callbackExecutor到EngineJob中,最后直接返回一個新的LoadStatus。添加了回調接口后,圖片資源下載成功后,可以回調本次添加ResourceCallback的onResourceReady方法。
(2) 如果緩存中沒有EngineJob,就新建一個EngineJob和DecodeJob,然后啟動DecodeJob任務。
4、engineJob.start(decodeJob)
EngineJob負責管理圖片請求回調,以及圖片下載完成后執行回調。
DecodeJob負責從磁盤緩存或數據源中加載原始數據并通過解碼器轉換為相應的資源類型。
class EngineJob<R> implements DecodeJob.Callback<R>,
Poolable {
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
//如果是要解碼磁盤的圖片資源,返回true, GlideExecutor為diskCacheExecutor,否則調用getActiveSourceExecutor()
//diskCacheExecutor為磁盤緩存加載線程池,不允許用于網絡操作
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 : 圖片源網絡加載線程池,沒有核心線程數, 線程數無限制
//animationExecutor : 動畫加載線程池
//sourceExecutor : 圖片源網絡加載線程池,有核心線程數,線程數有限
private GlideExecutor getActiveSourceExecutor() {
return useUnlimitedSourceGeneratorPool
? sourceUnlimitedExecutor : (useAnimationPool ? animationExecutor : sourceExecutor);
}
}
- GlideExecutor可能為diskCacheExecutor、sourceUnlimitedExecutor 、animationExecutor 、sourceExecutor其中一種,把DecodeJob提交給線程池執行。
- DecodeJob實現了Runnable接口,EngineJob的start方法就是啟動decodeJob的線程,執行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) {
//如果取消加載,調用notifyFailed()通知加載資源失敗
notifyFailed();
return;
}
runWrapped();
...
}
//decodeJob初始化時, runReason被設置為RunReason.INITIALIZE
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//判斷要解碼的數據來源,構建DataFetcherGenerator實例,執行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方法是要確定我們將要解碼的數據是來源于哪里的數據
//通常判斷順序為INITIALIZE -> RESOURCE_CACHE(圖片轉換之后的磁盤緩存) -> DATA_CACHE(原圖的磁盤緩存) -> SOURCE(數據源)
private Stage getNextStage(Stage current) {
switch (current) {
//INITIALIZE為Stage的初始狀態
case INITIALIZE:
// 如果decodeCachedResource() 為 true, 表示嘗試解碼緩存中已經被轉換的圖片
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:
// 如果調用者選擇只用緩存中檢索資源,則跳過從數據源加載
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
//根據Stage的枚舉值來獲取DataFetcherGenerator, 返回DataFetcherGenerator的子類
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
// 對應被轉換的圖片的緩存的 Generator
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
// 對應原始圖片的緩存的 Generator
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
// 對應圖片原始數據源的 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;
//這里判斷一下,之后主要是執行currentGenerator.startNext()方法執行后續的邏輯
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的內部枚舉類,用于表示所要解碼數據的來源(內存緩存, 磁盤緩存),初始化狀態是INITIALIZE。
- 這里首先是要調用getNextStage()方法確定需要解碼的數據來源,是緩存的圖片還是原始圖片;
- 根據要解碼的數據來源,構建對應的DataFetcherGenerator派生類(ResourceCacheGenerator, DataCacheGenerator等);DataFetcherGenerator負責構建DataFetcher實例, DataFetcher接口負責加載圖片數據。
- 啟動DataFetcherGenerator,調用DataFetcherGenerator的startNext()方法,構建DataFetcher。
- 默認情況下,一開始會調用ResourceCacheGenerator的startNext()方法,獲取磁盤緩存的數據。
- 如果磁盤沒有緩存到對應的圖片數據,要從數據源頭加載圖片時(比如從網絡加載圖片),會調用SourceGenerator的startNext()方法。
5、 SourceGenerator#startNext()
對應從數據源頭加載數據的場景,負責構建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;
//加載數據
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
}
- ModelLoader負責將多種復雜的數據模式轉變成DataFetcher可以加載的的具體資源類型。
- LoadData是ModelLoader的內部類,保存了圖片對應的唯一Key,備用key集合緩存,以及對應DataFetcher派生類。
- DataFetcher是真正負責加載資源的類,通過不同的派生類實現來加載不同的數據。
當我們加載網絡圖片源數據時,loadData.fetcher的實例是HttpUrlFetcher,即調用HttpUrlFetcher的loadData方法來加載網絡圖片源數據。
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());
//回調數據
callback.onDataReady(result);
...
}
//通過HttpURLConnection加載網絡圖片,返回圖片輸入流
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加載網絡圖片數據就是通過HttpURLConnection連接url,獲取圖片輸入流,然后通過回調接口把輸入流返回出去。callback.onDataReady()首先會回調SourceGenerator類的onDataReady()方法。
6、SourceGenerator#onDataReady()
當數據獲取成功后,需要執行的就是緩存圖片和把圖片設置到圖片控件上了。
//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構造函數傳遞進來的,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提交到線程池中執行,回調DecodeJob的run方法。
getActiveSourceExecutor().execute(job);
}
數據下載成功后,會經過很多的回調方法,回調過程為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會再次調用SourceGenerator的startNext方法
runGenerators();
break;
...
}
//SourceGenerator#startNext()
@Override
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
//把數據緩存到磁盤中
cacheData(data);
}
//執行了cacheData方法時,會把sourceCacheGenerator重新賦值為DataCacheGenerator。
//執行DataCacheGenerator的startNext方法
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
...
}
第二次運行DecodeJob線程,會再次調用SourceCacheGenerator的startNext方法,因為在數據下載成功的時候,把inputSteam賦值給了dataToCache,所以startNext方法首先調用cacheData()方法對數據進行磁盤緩存,然后調用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,調用其 loadData() 的時候又會把自身傳遞過去
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
DataCacheGenerator類中, loadData.fetcher的實例是ByteBufferFetcher對象,loadData.fetcher.loadData就是調用ByteBufferFetcher的loadData方法,同時DataCacheGenerator把對象自身作為回調接口傳遞給ByteBufferFetcher。
//ByteBufferFetcher#loadData()
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
//讀取緩存文件,獲取圖片文件的ByteBuffer數據
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
...
callback.onLoadFailed(e);
return;
}
//回調到DataCacheGenerator的onDataReady方法
callback.onDataReady(result);
}
//DataCacheGenerator#onDataReady()
@Override
public void onDataReady(Object data) {
//cb對象是SourceGenerator,所以又回調到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對象,所以再回調到DecodeJob的onDataFetcherReady()方法
cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
}
ByteBufferFetcher的loadData方法就是讀取圖片的磁盤緩存轉換成ByteBuffer數據,然后把數據回調給DecodeJob對象。
7、解析圖片數據:DecodeJob#onDataFetcherReady()
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey; //sourceKey是圖片的網絡url地址
this.currentData = data; //data是圖片數據,
this.currentFetcher = fetcher; //ByteBufferFetcher
this.currentDataSource = dataSource; //圖片的數據來源,為REMOTE,即遠端圖片數據源
this.currentAttemptingKey = attemptedKey; //attemptedKey和sourceKey一樣
if (Thread.currentThread() != currentThread) {
...
} else {
try {
// 調用 decodeFromRetrievedData 解析圖片數據
decodeFromRetrievedData();
}
...
}
}
//解析圖片數據
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
//currentFetcher為ByteBufferFetcher,
//currentData為圖片數據
//currentDataSource為DATA_DISK_CACHE
//解碼圖片數據,轉換成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();
}
}
//把圖片資源回調出去,然后根據options參數,緩存轉換的圖片到磁盤中。
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
if (resource instanceof Initializable) {
//resource對象為LazyBitmapDrawableResource實例,是BitmapResource的包裝類
//initialize方法是執行BitmapResource的initialize方法,執行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()) {
//根據options參數,緩存轉換的圖片到磁盤中
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
//編碼完成,釋放資源
onEncodeComplete();
}
//圖片資源獲取成功,回調出去
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
//callback為EngineJob的實例對象,回調到EngineJob的onResourceReady方法
callback.onResourceReady(resource, dataSource);
}
- onDataFetcherReady首先就是把圖片數據解析成Resource圖片包裝類。
- 把圖片資源回調給EngineJob對象,然后根據options參數,緩存轉換的圖片到磁盤中。
7.1 EngineJob#onResourceReady()
//在執行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實例對象,再回調到Engine的onEngineJobComplete方法
listener.onEngineJobComplete(this, localKey, localResource);
for (final ResourceCallbackAndExecutor entry : copy) {
//把cb回調傳遞給CallResourceReady,并執行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實例對象,回調到SingleRequest的onResourceReady方法中
cb.onResourceReady(engineResource, dataSource);
}
...
}
- 先把Resource對象包裝成EngineResource。
- listener.onEngineJobComplete()方法會回調到Engine#onEngineJobComplete()的方法,把EngineResource對象回調給Engine。
- entry.executor.execute(new CallResourceReady(entry.cb))啟動CallResourceReady線程。cb是SingleRequest實例對象,回調到SingleRequest的onResourceReady方法中,并且把EngineResource資源對象傳遞給SingleRequest對象。
8、Engine#onEngineJobComplete()
對EngineResource執行緩存操作。
@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實現了ResourceListener的接口
//記錄key和ResourceListener接口的實現類(Engine類實例對象)到EngineResource對象中
//當EngineResource的release方法被執行時,會回調ResourceListener的onResourceReleased方法,即回調到Engine類的onResourceReleased方法中
resource.setResourceListener(key, this);
//把數據緩存到activeResources中,Glide的第一級緩存,軟引用緩存
if (resource.isCacheable()) {
activeResources.activate(key, resource);
}
}
jobs.removeIfCurrent(key, engineJob);
}
//當EngineResource對象的release方法執行時,回調到此方法
@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方法會回調Engine的onResourceReleased方法,從一級緩存中刪除EngineResource,然后保存到二級緩存中。
- 然后把EngineResource保存到Glide的一級緩存activeResources中。
9、SingleRequest#onResourceReady()
@Override
public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
...
Object received = resource.get();//從EngineResource中獲取BitmapDrawable對象
...
//調用onResourceReady重載方法
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
...
status = Status.COMPLETE;//設置狀態為完成狀態
...
isCallingCallbacks = true;
try {
boolean anyListenerHandledUpdatingTarget = false;
...
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
//target為DrawableImageViewTarget,
//回調target的onResourceReady方法,最后會回調DrawableImageViewTarget的setResource方法
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
//BitmapImageViewTarget#setResource
@Override
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);//給控件設置bitmap圖像
}
SingleRequest的onResourceReady方法會回調用target的onResourceReady方法,由于target是DrawableImageViewTarget的實例,最終會回調到BitmapImageViewTarget的setResource方法,給view設置bitmap資源。
總結: into(imageView)的大體流程如下。
1、首先構建圖片控件的包裝類ViewTarget,實例為DrawableImageViewTarget或者BitmapImageViewTarget。
2、構建request,獲取SingleRequest實例對象,并執行reqest.begin方法開始請求。
3、構建EngineJob和DecodeJob,通過EngineJob啟動decodeJob的任務。
4、構建DataFetcher實例,通過HttpUrlConnection請求圖片網絡url,獲取圖片輸入流,并把輸入流回調出去。
5、緩存圖片到磁盤中,繼續回調圖片流。
6、解析圖片數據,轉換成EngineResource圖片包裝類。
7、緩存圖片到Glide的一級緩存中,并設置后EngineResource釋放時,緩存圖片到二級緩存中。
8、設置圖片資源到圖片控件中。