引子
基本使用:
A = Glide.with(activity)
.load(url)
.into(image);
流程概述
抽象出 Request、Target:
- 封装url到Request中,封装imageView到Target中,Request和Target相互持有;
-
调用Engine.load()启动加载;
@startuml
: Glide.with(activity);
: RequestManager.load(url);
: RequestBuilder.into(imageView);
: imageView -> Target;
: (url, target) -> Request;
: RequestManager.track(target, request);
: RequestTracker.runRequest(request);
: Request.begin();
: Engine.load();
: Request.onResourceReady(resource, dataSource);
: Target.onResourceReady(result, animation);
: image.setImageDrawable;
@enduml
加载主流程:
- 加载一级内存缓存activeCache;
- 加载二级内存缓存lruCache;
-
executeDecodeJob,异步从文件缓存或网络中加载图片;
@startuml
: "Engine.load()";
if (activeCache != null) then (yes)
: cb.onResourceReady(activeCache);
else if(lruCache != null) then (yes)
: cb.onResourceReady(lruCache);
else
: runexecute DecodeJob;
: onDecodeComplete;
: cb.onResourceReady(decodeResource);
endif
:end;
@enduml
DecodeJob
DecodeJob 继承 Runnable,在线程池中执行。它会依次通过DataFetcherGenerator的三个实现类取数据,它们分别是:
- ResourceCacheGenerator 获取一级文件缓存,缓存后期处理(压缩、变形)过的图片。
- DataCacheGenerator 获取二级文件缓存,缓存原始文件。
-
SourceGenerator 获取原始数据(网络)。
获取到数据之后(此时数据的形态可能是InputSteam),接下来会进行Decode,把Stream转换成需要的图片格式(Bitmap,Drawable)
@startuml
:DecodeJob.run();
#yellow: fetch data;
:DataFetcherGenerator.startNext();
:ResourceCacheGenerator.startNext();
:DecodeHelper.getDiskCache() -> DiskCache;
:DiskCache.get() -> cache file;
:DecodeHelper.getModelLoaders() -> ModelLoader;
:ModelLoader.buildLoadData() -> LoadData;
:LoadData.fetcher -> DataFetcher;
:Fetcher.loadData();
:ResourceCacheGenerator.onDataReady();
:DecodeJob.onDataFetcherReady();
#yellow:decode data;
:DecodeJob.decodeFromRetrievedData();
:LoadPath.load();
:DecodePath.decode();
:EngineJob.onResourceReady()
handler post message to main thread in this method;
:Engine.onEngineJobComplete()
SingleRequest.onResourceReady();
@enduml
源码详细分析
Glide.with -> RequestManager
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
//...
return Glide.get(context).getRequestManagerRetriever();
}
RequestManagerRetriever
/**
* A collection of static methods for creating new {@link com.bumptech.glide.RequestManager}s or
* retrieving existing ones from activities and fragment.
*/
RequestManager.load -> RequestBuilder
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
RequestBuilder#into
load()
public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
return loadGeneric(bitmap)
.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
into()
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,
BaseRequestOptions<?> options) {
//...
Request request = buildRequest(target, targetListener, options)
//..
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
buildRequest()
最终会走到下面的代码,返回的其实Request
的实现类SingleRequest
private Request obtainRequest(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> 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());
}
RequestManager#track(target, request);
void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
RequestTracker#runRequest(request);
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
pendingRequests.add(request);
}
}
SingleRequest#begin();
public void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
//...
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
//..
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
//...
}
实际的加载在这里 SingleRequest#onSizeReady(overrideWidth, overrideHeight);
public void onSizeReady(int width, int height) {
//..
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);
//..
}
Engine#load()
public <R> LoadStatus load(
GlideContext glideContext,
//..
ResourceCallback cb) {
Util.assertMainThread();
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
// active cache
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;
}
// cache
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);
// start decode
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
EngineJob#start()
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
// 根据需要选择不同的executor
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
DecodeJob implement Runnable
@Override
public void run() {
//..
runWrapped();
//..
}
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 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);
}
}
private void decodeFromRetrievedData() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Retrieved data", startFetchTime,
"data: " + currentData
+ ", cache key: " + currentSourceKey
+ ", fetcher: " + currentFetcher);
}
Resource<R> resource = null;
try {
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
ResourceCacheGenerator#startNext()
public boolean startNext() {
cacheFile = helper.getDiskCache().get(currentKey);
modelLoaders = helper.getModelLoaders(cacheFile);
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData = modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
loadData.fetcher.loadData(helper.getPriority(), this);
//..
}
HttpGlideUrlLoader
HttpUrlFetcher
@Override
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
//..
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
//..
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
Map<String, String> headers) throws IOException {
//..
urlConnection = connectionFactory.build(url);
//..
urlConnection.connect();
stream = urlConnection.getInputStream();
if (isHttpOk(statusCode)) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (isHttpRedirect(statusCode)) {
//..
}
}