Glide是一个图片加载框架,使用方法如下:
添加依赖:
implementation "com.github.bumptech.glide:glide:$glide_version"
annotationProcessor "com.github.bumptech.glide:compiler:$glide_version"
Glide版本号参考Glide地址:https://github.com/bumptech/glide
使用方式如下:
//图片的URL
var imageUrl = "xxxxxxx"
Glide.with(this).load(imageUrl).into(dataBinding.imageView)
本文主旨介绍Glide加载网络图片的流程,不过多介绍Glide的生命周期、图片变换及图片缓存。
Glide的工作流程
首先,根据给定的图片URL创建一个图片加载请求(以加载网络图片为例)。然后,在子线程执行图片加载请求,获取图片的输入流,将输入流解析为图片(Bitmap),并对得到的图片进行变换和保存处理。最后,将图片回调至主线程,进行展示。
Glide加载网络图片的工作流程图如下所示:
Glide加载图片流程概述
一、创建图片加载请求
首先、调用Glide的with方法,此方法会触发Glide的初始化,初始化Glide的各种线程池、图片解码编码器、 图片加载器等。然后、调用load(url)方法,此方法会返回一个RequestBuilder,以构造图片加载请求。Glide采用建造者模式来创建图片加载请求。最后,调用Glide的into(ImageView)方法,此方法首先将ImageView封装到ViewTarget中,ViewTarget可以看作一个回调接口,在图片加载完成后,会将加载到的图片放到ImageView中;然后,构建图片加载请求,并通知请求管理器(ReuqestManager)执行此图片加载请求。
二、执行图片加载请求
图片加载请求(Request)构建完成之后,Glide会通知请求管理器去执行此图片加载请求。请求执行过程为:首先,根据图片加载策略(本地或远程加载),获取DataFetcherGenerator,顾名思义,DataFetcherGenerator是用来生成DataFetcher的,而DataFetcher是一个用来获取图片数据的接口。例如,策略为通过网络加载,则得到是SourceGenerator,其为DataFetcherGenerator的子类。然后,DataFetcherGenerator会构造出指定类型的DataFetcher,并使用DataFetcher来加载图片数据。最后,将图片数据交给回调接口。
以加载网络图片来说明上述过程。若为加载网络图片,则得到的DataFetcher生成器为SourceGenerator。SourceGenerator首先会根据图片的URL(URL在Glide中会变化为model),获取ModelLoader,ModelLoader的目的是将Model转化为图片数据(Data)。然后,Glide通过ModelLoader构造出包含DataFetcher的LoadData,加载网络图片的DataFetcher是HttpUrlFetcher,LoadData则包含了缓存图片时用的key及加载图片的DataFetcher对象。最后,在得到图片输入流后,将其交给回调接口,回调接口的作用是将图片输入流转化为图片,并对图片进行变化和缓存处理。
在此介绍一下Glide如何通过model获取ModelLoader。Glide在初始化时,会将全部的种类的ModelLoader存储到ModelLoaderRegistry,与ModelLoader一同存储的还有Model和Data的类型。前面也提到过ModelLoader的目的就是将Model转化为Data。这里Model可以看作是URI,Data可以看作是URI对应的资源。比如,加载网络图片时,Model是字符串,其类型是String,Data是图片输入流,其类型是InputStream,ModelLoader则是将图片URL转化为图片输入流。这样,在获取ModelLoader时,Glide会遍历ModelLoaderRegistry中存储的ModelLoader,并检查ModelLoader是否能够处理Model,若能够处理,则将其添加到返回结果集合中。实际上,Glide在初始化时,并没有直接将ModelLoader对象存储到ModelLoader中,而是存储了ModelLoader的构造器,即xxxxxFactory,这样在第一次从ModelLoaderRegistry中读取ModelLoader时,会先调用xxxxFactory的构造方法来构造ModelLoader,然后再将ModelLoader保存到ModelLoaderRegistry中。
在得到图片数据后,Glide会使用ResourceDecoder将图片数据(Data)转化为图片(Resource)。比如,加载网络图片时,在得到图片的输入流后,会调用BitmapDrawableDecoder的decode方法将输入流转化为BitmapDrawable,BitmapDrawableDecoder为ResourceDecoder的子类。在得到图片之后,Glide会对图片进行变化和缓存处理,本文不对此进行过多介绍。
三、展示图片
在加载图片时,Glide首先创建了一个DecodeJob对象(实现了Runnable),运行在子线程以加载、变化及缓存图片。然后,创建了一个EngineJob实现并注册了DecodeJob的回调接口,这样就可以得到处理后的图片,并将图片展示任务通过Handler发送到了主线程。
接下来,将对上述3个过程进行详细介绍。
一、创建图片加载请求
1.1、初始化Glide
Glide在加载图片之前,会先构造图片加载请求,而在构造加载请求之前,通常会先初始Glide框架。例如,在调用Glide的with方法时,会对Glide进行初始化。
Glide.with(this)
此方法的返回结果为RequestManager,用来创建图片加载请求。此方法最终会调用Glide的get方法,如下所示:
public static Glide get(@NonNull Context context) {
if (glide == null) {
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
//初始化Glide
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
chechAndInitializeGlide方法首先会进行一些检查。然后,调用GlideBuilder的build方法创建一个Glide对象,并将其设置为单实例。build方法代码如下:
Glide build(@NonNull Context context) {
if (this.sourceExecutor == null) {
//创建加载图片的线程
this.sourceExecutor = GlideExecutor.newSourceExecutor();
}
if (this.diskCacheExecutor == null) {
this.diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
......
if (this.engine == null) {
this.engine = new Engine(this.memoryCache, this.diskCacheFactory, this.diskCacheExecutor, this.sourceExecutor, GlideExecutor.newUnlimitedSourceExecutor(), this.animationExecutor, this.isActiveResourceRetentionAllowed);
}
......
GlideExperiments experiments = this.glideExperimentsBuilder.build();
RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(this.requestManagerFactory, experiments);
//创建Glide
return new Glide(context, this.engine, this.memoryCache, this.bitmapPool, this.arrayPool, requestManagerRetriever, this.connectivityMonitorFactory, this.logLevel, this.defaultRequestOptionsFactory, this.defaultTransitionOptions, this.defaultRequestListeners, experiments);
}
在此只展示一些和图片加载相关的代码。首先,此方法会创建用于加载网络图片的线程池。然后,创建Glide对象。Glide的此构造方法较长,因此只展示以下部分:输入流转化为Bitmap的解码器、输入流转化为BitmapDrawable的解码器及将URL转化为图片输入流的转化器(ModelLoader)。
Glide(
@NonNull Context context,
@NonNull Engine engine,
@NonNull MemoryCache memoryCache,
@NonNull BitmapPool bitmapPool,
@NonNull ArrayPool arrayPool,
@NonNull RequestManagerRetriever requestManagerRetriever,
@NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
int logLevel,
@NonNull RequestOptionsFactory defaultRequestOptionsFactory,
@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
@NonNull List<RequestListener<Object>> defaultRequestListeners,
GlideExperiments experiments) {
this.engine = engine;
this.bitmapPool = bitmapPool;
this.arrayPool = arrayPool;
this.memoryCache = memoryCache;
this.requestManagerRetriever = requestManagerRetriever;
this.connectivityMonitorFactory = connectivityMonitorFactory;
this.defaultRequestOptionsFactory = defaultRequestOptionsFactory;
final Resources resources = context.getResources();
registry = new Registry();
......
// TODO(judds): Make ParcelFileDescriptorBitmapDecoder work with ImageDecoder.
Downsampler downsampler =
new Downsampler(
registry.getImageHeaderParsers(), resources.getDisplayMetrics(), bitmapPool, arrayPool);
ResourceDecoder<ByteBuffer, Bitmap> byteBufferBitmapDecoder;
ResourceDecoder<InputStream, Bitmap> streamBitmapDecoder;
if (experiments.isEnabled(EnableImageDecoderForBitmaps.class)
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
//创建将数据流转化为Bitmap的解码器
streamBitmapDecoder = new InputStreamBitmapImageDecoderResourceDecoder();
byteBufferBitmapDecoder = new ByteBufferBitmapImageDecoderResourceDecoder();
} else {
byteBufferBitmapDecoder = new ByteBufferBitmapDecoder(downsampler);
streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);
}
......
registry
.append(ByteBuffer.class, new ByteBufferEncoder())
.append(InputStream.class, new StreamEncoder(arrayPool))
/* Bitmaps */
.append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder)
//保存 “将数据流转为Bitmap”的解码器
.append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder);
......
registry
.append(
Registry.BUCKET_BITMAP,
ParcelFileDescriptor.class,
Bitmap.class,
parcelFileDescriptorVideoDecoder)
......
/* BitmapDrawables */
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
ByteBuffer.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, byteBufferBitmapDecoder))
//保存“将数据流转化为BitmapDrawable”的解码器
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
InputStream.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, streamBitmapDecoder))
.......
if (ParcelFileDescriptorRewinder.isSupported()) {
registry.register(new ParcelFileDescriptorRewinder.Factory());
}
registry
.append(int.class, InputStream.class, resourceLoaderStreamFactory)
.......
.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
.append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
//添加StringLoader(ModelLoader的子类)的构建者,StringLoader可以将String类的Model
//转化为InputStream类型的Data
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
.append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
......
registry
.append(Uri.class, InputStream.class, new UriLoader.StreamFactory(contentResolver))
......
//添加UrlUriLoader的构建者,可以看出其会将Uri类的Model转化为InputStream类的Data
.append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())
.append(URL.class, InputStream.class, new UrlLoader.StreamFactory())
.append(Uri.class, File.class, new MediaStoreFileLoader.Factory(context))
//添加HttpGlideUrlLoader的构建者,HttpGlideUrlLoader负责将图片的GlideUrl
//转为图片输入流。上面介绍的几类ModelLoader最终都会将获取图片输入流的任务委托
//给HttpGlideUrlLoader
.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
......
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
glideContext =
new GlideContext(
context,
arrayPool,
registry,
imageViewTargetFactory,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
engine,
experiments,
logLevel);
}
1.2、创建图片加载请求
在Glide初始化结束后,接下来就要创建图片加载请求。Glide采用建造者模式来创建图片加载请求(Request)。图片加载请求的创建主要分为2步,首先,创建请求构造者(RequestBuilder),若有图片变化需求,则可以对RequestBuilder进行配置(调用centerCrop等方法)。然后,RequestBuilder根据给定的配置构建图片加载请求(SingleRequestt)。
1)创建ReuqestBuilder
Glide的load方法会创建一个ReuqestBuilder,代码如下:
public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
return this.asDrawable().load(drawable);
}
@NonNull
@CheckResult
//根据之前的例子,会调用此load方法
public RequestBuilder<Drawable> load(@Nullable String string) {
return this.asDrawable().load(string);
}
@NonNull
@CheckResult
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return this.asDrawable().load(uri);
}
@NonNull
@CheckResult
public RequestBuilder<Drawable> load(@Nullable File file) {
return this.asDrawable().load(file);
}
@NonNull
@CheckResult
public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return this.asDrawable().load(resourceId);
}
Glide中存在多个重载的load方法,以实现多态性。根据上面的例子,最终会调用参数为String类型的load方法。接着,调用asDrawable方法,代码如下:
public RequestBuilder<Drawable> asDrawable() {
return this.as(Drawable.class);
}
此方法会去调用as方法,并闯入Drawable.class。as方法代码如下:
public <ResourceType> RequestBuilder<ResourceType> as(@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder(this.glide, this, resourceClass, this.context);
}
可以看出as方法会创建一个ReuqestBuilder,这里resourceClass的类型时Drawable.class,表示最终需要得到一个Drawable类型的图片。
2)、创建图片加载请求Request
当调用Glide的into方法时,会创建一个Request,代码如下:
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
......
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
此方法首先,将ImageView封装到ViewTarget中。然后,去调用了另一个重载的into方法,这里注意最后一个参数为主线程的线程池,意味着在图片加载完成后,会将得到的图片放到此主线程池中处理。重载的into方法代码如下:
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//创建Reuqest
Request request = buildRequest(target, targetListener, options, callbackExecutor);
......
requestManager.clear(target);
target.setRequest(request);
//执行Request,加载图片
requestManager.track(target, request);
return target;
}
可以看出此方法首先会,调用buildRequest方法来构建Request。然后,调用RequestManager的track方法去执行Request,加载图片。这里先给出track方法代码:
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
this.targetTracker.track(target);
this.requestTracker.runRequest(request);
}
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
//执行Request
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
在此会调用Request的begin方法来执行Request,而Request是一个接口,具体的Request实例由buildRequest方法返回。buildRequest方法代码如下:
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
/*requestLock=*/ new Object(),
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
接着调用buildRequestRecursive方法,代码如下:
private Request buildRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
......
Request mainRequest =
buildThumbnailRequestRecursive(
requestLock,
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
......
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
private Request buildThumbnailRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
if (thumbnailBuilder != null) {
......
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
......
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// Base case: no thumbnail.
//调用此方法
return obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
接下来,会调用obtainRequest方法,代码如下:
private Request obtainRequest(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model, //图片的URL
transcodeClass, //Drawable.class
requestOptions,
overrideWidth,
overrideHeight,
priority,
target, //之前封装的ViewTarget
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);//主线程池
}
可以看到,最终构建了一个SingleRequest实例,来表示图片加载请求。
二、执行图片加载请求
2.1、进行网络请求,获取图片的数据流
在上节简单提过,在得到Request后,会调用Request的begin方法来执行图片加载。针对加载网络图片,得到Request为SingleRequest,其begin方法代码如下:
public void begin() {
synchronized (requestLock) {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
......
return;
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
if (status == Status.COMPLETE) {
onResourceReady(
resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//调用此方法
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
......
}
}
接着会调用onSizeReady方法,其代码如下:
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
......
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,
callbackExecutor);
......
}
}
接下来回调用Engine的load方法,代码如下:
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass, //Obect.class
Class<R> transcodeClass, //Drawable.class
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable, //true
boolean useUnlimitedSourceExecutorPool, //false
boolean useAnimationPool, //false
boolean onlyRetrieveFromCache, //false 上述值可以通过Debug模式看到
ResourceCallback cb,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
waitForExistingOrStartNewJob方法代码如下:
private <R> LoadStatus waitForExistingOrStartNewJob(
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,
Executor callbackExecutor,
EngineKey key,
long startTime) {
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
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);
//将engineJon注册为回调接口,当decodeJob完成工作时,会通知engineJob将图片发到主线程处理
jobs.put(key, engineJob);
//callbackExecutor即主线程池
engineJob.addCallback(cb, callbackExecutor);
//开始加载图片
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
在此会通过engineJob的start方法启动图片加载任务,start方法代码如下:
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
可以看到,此方法会选择一个线程池去执行decodeJob,因为是从网络获取图片,所以executor从getActiveSourceExecutor()方法中获取,其代码为:
private GlideExecutor getActiveSourceExecutor() {
//这几个变量是从engine.load方法传入的,前面已经说明了这几个变量的值
//综合分析,返回值为sourceExecutor,这个线程池在Glide初始化时会被初始化,之前已简单介绍
return useUnlimitedSourceGeneratorPool
? sourceUnlimitedExecutor
: (useAnimationPool ? animationExecutor : sourceExecutor);
}
接下来decodeJob会在sourceExecutor线程池中运行,以加载并处理图片,具体运行代码如下:
public void run() {
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (CallbackException e) {
// If a callback not controlled by Glide throws an exception, we should avoid the Glide
// specific debug logic below.
throw e;
} catch (Throwable t) {
......
}
}
runWrapped方法代码如下:
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
//获取DataFetcher生成器
currentGenerator = getNextGenerator();
//加载网络图片并处理
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
此方法首先会调用getNextGenerator方法,其代码如下:
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
//因为是从网络加载图片,所以返回SourceGenerator
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
接下来,会调用runGenerators方法,代码如下:
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
......
}
在此方法中,会调用sourceGenerator的startNext方法来加载图片,代码如下:
public boolean startNext() {
......
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
//获取LoadData,前面介绍过了,LoadData中包含了可以获取图片数据的DataFetcher
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//获取图片数据
startNextLoad(loadData);
}
}
return started;
}
此方法首先,寻找能够加载图片的loadData,可能会得到多个种类的LoadData。然后,调用startNextLoad方法,并将得到的loadData传入,以尝试使用这多个LoadData去加载图片,直至图片加载成功。
1)、查找loadData(getLoadData()方法)
此过程的大概流程为:首先,根据Model(即之前传入的图片URL),找出可以处理此Model的一组ModelLoader。然后,调用ModelLoader的buildLoadData方法构造LoadData。最后,就可以得到一组LoadData了。注意:在调用ModelLoader的buildLoadData方法构造LoadData时,存在一些委派构造的情况,即有些ModelLoader会委派其他ModelLoader去构造LoadData,而非直接构造LoadData。在委派构造时,ModelLoader并没有直接持有受委派的ModelLoader的引用,而是使用了一个MultiModelLoaderFactory类的全局实例,通过调用其build方法,并传不同的参数,以构造出不同的LoadData。
接下来,通过代码进行解释。getLoadData方法代码如下:
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
//根据Model,获取能够转化Model的ModelLoader
List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
//遍历得到的ModelLoader,并用其构造LoadData
for (int i = 0, size = modelLoaders.size(); i < size; i++) {
ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
LoadData<?> current = modelLoader.buildLoadData(model, width, height, options);
if (current != null) {
loadData.add(current);
}
}
}
return loadData;
}
getModelLoader方法代码如下:
public <Model> List<ModelLoader<Model, ?>> getModelLoaders(@NonNull Model model) {
return modelLoaderRegistry.getModelLoaders(model);
}
public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
//根据Model类型,获取可以处理此Model类型的ModelLoader
//如Model的类型为String,则返回的可能包含以下ModelLoader:
//DataUrlLoader、StringLoader等
List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
if (modelLoaders.isEmpty()) {
throw new NoModelLoaderAvailableException(model);
}
int size = modelLoaders.size();
boolean isEmpty = true;
List<ModelLoader<A, ?>> filteredLoaders = Collections.emptyList();
//对上述获取的ModelLoader进行过滤。
//例如,model为图片URL,则会将DataUrlLoader过滤掉,只保留StringLoader
for (int i = 0; i < size; i++) {
ModelLoader<A, ?> loader = modelLoaders.get(i);
//检查ModelLoader是否能够真正处理model
if (loader.handles(model)) {
if (isEmpty) {
filteredLoaders = new ArrayList<>(size - i);
isEmpty = false;
}
filteredLoaders.add(loader);
}
}
if (filteredLoaders.isEmpty()) {
throw new NoModelLoaderAvailableException(model, modelLoaders);
}
return filteredLoaders;
}
此方法首先,调用getModelLoadersForClass方法,以获取可以处理Model类型的ModelLoader。然后,对ModelLoader进行过滤,以保留真正可以处理Model的ModelLoader。getModelLoadersForClass方法代码如下:
private synchronized <A> List<ModelLoader<A, ?>> getModelLoadersForClass(
@NonNull Class<A> modelClass) {
List<ModelLoader<A, ?>> loaders = cache.get(modelClass);
if (loaders == null) {
//build方法代码如下
loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));
cache.put(modelClass, loaders);
}
return loaders;
}
synchronized <Model> List<ModelLoader<Model, ?>> build(@NonNull Class<Model> modelClass) {
try {
List<ModelLoader<Model, ?>> loaders = new ArrayList<>();
//Entry中包含了3部分信息,分别是Model、Data以及ModelLoaderFacotry
//entries中的这些信息,其实在Glide初始化就进行了保存,详见上一节“Glide初始化”
for (Entry<?, ?> entry : entries) {
//避免方法递归时栈溢出
if (alreadyUsedEntries.contains(entry)) {
continue;
}
//过滤能够处理Model的Entry,并使用Entry中的ModelLoaderFactory构造ModelLoader
if (entry.handles(modelClass)) {
alreadyUsedEntries.add(entry);
loaders.add(this.<Model, Object>build(entry));
alreadyUsedEntries.remove(entry);
}
}
return loaders;
} catch (Throwable t) {
alreadyUsedEntries.clear();
throw t;
}
}
这样就得到了一组可以处理Model的ModelLoader,接下来调用ModelLoader的buildLoadData方法来构建LoadData。结合Model的类型(即String)与Glide初始化时添加的ModelLoader构造器,通过分析可知,与加载网络图片相关的ModelLoader时StringLoader,所以下面只展示StringLoader的buildLoadData方法:
public class StringLoader<Data> implements ModelLoader<String, Data> {
private final ModelLoader<Uri, Data> uriLoader;
// Public API.
@SuppressWarnings("WeakerAccess")
public StringLoader(ModelLoader<Uri, Data> uriLoader) {
this.uriLoader = uriLoader;
}
@Override
public LoadData<Data> buildLoadData(
@NonNull String model, int width, int height, @NonNull Options options) {
//将字符串解析为Uri
Uri uri = parseUri(model);
if (uri == null || !uriLoader.handles(uri)) {
return null;
}
return uriLoader.buildLoadData(uri, width, height, options);
}
......
}
可以看到这里调用了UriLoader的buildLoadData方法,以构造一个LoadData。这就是前面说的委派构造。uriLoader是在构造StringLoader时传入的,所以看下StringFactory如何构造StringLoader,构造代码如下:
public static class StreamFactory implements ModelLoaderFactory<String, InputStream> {
@NonNull
@Override
public ModelLoader<String, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
//通过multifacotry的build方法构建了一个ModelLoader,注意这里的Model类型发生了变化
//由String类型变为了Uri类型
return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));
}
@Override
public void teardown() {
// Do nothing.
}
}
接下来看下MultiModelLoaderFactory的build方法,代码如下:
public synchronized <Model, Data> ModelLoader<Model, Data> build(
@NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass) {
try {
List<ModelLoader<Model, Data>> loaders = new ArrayList<>();
boolean ignoredAnyEntries = false;
//entries中的数据,在Glide初始化时被赋值
for (Entry<?, ?> entry : entries) {
if (alreadyUsedEntries.contains(entry)) {
ignoredAnyEntries = true;
continue;
}
if (entry.handles(modelClass, dataClass)) {
alreadyUsedEntries.add(entry);
loaders.add(this.<Model, Data>build(entry));
alreadyUsedEntries.remove(entry);
}
}
if (loaders.size() > 1) {
//可以获取一组能够将Uri转化为InputStream的ModeLoader(详见Glide初始化),我们主要关注UrlUriLoader
//因此将这些ModelLoader封装到MultiModelLoader中
//此build方法代码如下
return factory.build(loaders, throwableListPool);
} else if (loaders.size() == 1) {
return loaders.get(0);
} else {
......
}
} catch (Throwable t) {
alreadyUsedEntries.clear();
throw t;
}
}
static class Factory {
@NonNull
public <Model, Data> MultiModelLoader<Model, Data> build(
@NonNull List<ModelLoader<Model, Data>> modelLoaders,
@NonNull Pool<List<Throwable>> throwableListPool) {
return new MultiModelLoader<>(modelLoaders, throwableListPool);
}
}
可以看出,最终会调用此MultiModelLoader类的buildLoadData方法,其代码如下:
public LoadData<Data> buildLoadData(
@NonNull Model model, int width, int height, @NonNull Options options) {
Key sourceKey = null;
int size = modelLoaders.size();
List<DataFetcher<Data>> fetchers = new ArrayList<>(size);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0; i < size; i++) {
ModelLoader<Model, Data> modelLoader = modelLoaders.get(i);
//使用model对得到的ModelLoader进行过滤,在本文分析的情况中,最终只有
//UrlUriLoader通过过滤(因为model是一个图片的URL)
if (modelLoader.handles(model)) {
//调用UrlUriLoader的buildLoadData(委派形式)
LoadData<Data> loadData = modelLoader.buildLoadData(model, width, height, options);
if (loadData != null) {
sourceKey = loadData.sourceKey;
fetchers.add(loadData.fetcher);
}
}
}
return !fetchers.isEmpty() && sourceKey != null
? new LoadData<>(sourceKey, new MultiFetcher<>(fetchers, exceptionListPool))
: null;
}
可以看出此方法首先,对得到的ModelLoader进行了过滤,经过分析,发现只有UrlUriLoader通过过滤。然后,调用了UrlUriLoader的buildLoadData方法,以生成LoadData,此方法代码如下:
public LoadData<Data> buildLoadData(
@NonNull Uri uri, int width, int height, @NonNull Options options) {
GlideUrl glideUrl = new GlideUrl(uri.toString());
return urlLoader.buildLoadData(glideUrl, width, height, options);
}
可以看出,此方法也是采用委派构造的形式,其委派过程与上述过程相似,因此不再赘述。在此,直接给出最终的LoadData,如下所示:
public LoadData<InputStream> buildLoadData(
......
int timeout = options.get(TIMEOUT);
//最终的LoadData
return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
可以看出,在加载网络图片时,LoadData是使用HttpUrlFetcher来加载图片数据的。
2)、加载网络图片(startNextLoad()方法)
在得到loadData之后,可以调用startNextLoad方法加载图片数据,此方法代码如下:
private void startNextLoad(final LoadData<?> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {
@Override
public void onDataReady(@Nullable Object data) {
if (isCurrentRequest(toStart)) {
onDataReadyInternal(toStart, data);
}
}
@Override
public void onLoadFailed(@NonNull Exception e) {
if (isCurrentRequest(toStart)) {
onLoadFailedInternal(toStart, e);
}
}
});
}
可以看到,此方法使用loadData中的fetcher(DataFetcher)来加载图片,根据前面的分析可知,此fetcher的类型为HttpUrlFetcher,其loadData方法代码如下:
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
//获取图片的输入流
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
//通过回调处理图片输入流
callback.onDataReady(result);
} catch (IOException e) {
......
} finally {
......
}
}
此方法会调用loadDataWithRedirects方法去获取图片的输入流,最终会通过HttpURLConnetion来获取图片的输入流。在此,本文就不再继续往下分析图片的网络传输过程。在得到图片输入流之后,Glide会使用之前注册的回调接口(DataCallback)进行处理。
2.2、将数据流转化为图片(Bitmap)
在得到图片输入流之后,会通过回调接口DataCallback,将输入流交给DecodeJob处理。DataCallback代码如下:
private void startNextLoad(final LoadData<?> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {
@Override
public void onDataReady(@Nullable Object data) {
if (isCurrentRequest(toStart)) {
onDataReadyInternal(toStart, data);
}
}
......
});
}
void onDataReadyInternal(LoadData<?> loadData, Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
// We might be being called back on someone else's thread. Before doing anything, we should
// reschedule to get back onto Glide's thread.
cb.reschedule();
} else {
//回调decodeJob的方法
cb.onDataFetcherReady(
loadData.sourceKey,
data,
loadData.fetcher,
loadData.fetcher.getDataSource(),
originalKey);
}
}
onDataFetcherReady方法的代码如下:
public void onDataFetcherReady(
Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
this.isLoadingFromAlternateCacheKey = sourceKey != decodeHelper.getCacheKeys().get(0);
if (Thread.currentThread() != currentThread) {
......
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
//对图片输入流进行解码
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
decodeFromRetrivedData方法代码如下:
private void decodeFromRetrievedData() {
......
Resource<R> resource = null;
try {
//将输入流解码为BitmapDrawable
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
//通知主线程处理得到的BitmapDrawable
notifyEncodeAndRelease(resource, currentDataSource, isLoadingFromAlternateCacheKey);
} else {
runGenerators();
}
}
decodeFromData方法的目的是解码图片,最终会调用decodeFromFetcher方法,其代码如下:
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
throws GlideException {
//获取可以将输入流解码为BitmapDrawable的解码器
LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
//将输入流解码为BitmapDrawable
return runLoadPath(data, dataSource, path);
}
上述代码做了2件事,一是根据data的类型,获取可以将data解码为图片的解码器,经过前面的分析,可知这里的data类型为InputStream。二是使用图片解码器,解码data。
1)、获取图片解码器
获取图片解码器的大体过程为:首先,根据data的类型和最终图片的类型(Drawable),找出能够处理此data的解码器。然后,将此解码器封装到DecodePath中。最后,将DecodePath封装到LoadPath中,并将LoadPath返回。
接下来通过代码解释上述过程。getLoadPath方法的代码如下:
<Data> LoadPath<Data, ?, Transcode> getLoadPath(Class<Data> dataClass) {
//dataClass的类型为InputStream,resourceClass为Object,transcodeClass为Drawable
return glideContext.getRegistry().getLoadPath(dataClass, resourceClass, transcodeClass);
}
接下来会调用Registry的getLoadPath方法,代码如下:
public <Data, TResource, Transcode> LoadPath<Data, TResource, Transcode> getLoadPath(
@NonNull Class<Data> dataClass,
@NonNull Class<TResource> resourceClass,
@NonNull Class<Transcode> transcodeClass) {
LoadPath<Data, TResource, Transcode> result =
loadPathCache.get(dataClass, resourceClass, transcodeClass);
if (loadPathCache.isEmptyLoadPath(result)) {
return null;
} else if (result == null) {
//获取包含解码器的DecodePaths
List<DecodePath<Data, TResource, Transcode>> decodePaths =
getDecodePaths(dataClass, resourceClass, transcodeClass);
if (decodePaths.isEmpty()) {
result = null;
} else {
//将得到的DecodePath封装到LoadPath中
result =
new LoadPath<>(
dataClass, resourceClass, transcodeClass, decodePaths, throwableListPool);
}
loadPathCache.put(dataClass, resourceClass, transcodeClass, result);
}
return result;
}
getDecodePaths方法的代码如下:
private <Data, TResource, Transcode> List<DecodePath<Data, TResource, Transcode>> getDecodePaths(
@NonNull Class<Data> dataClass,
@NonNull Class<TResource> resourceClass,
@NonNull Class<Transcode> transcodeClass) {
List<DecodePath<Data, TResource, Transcode>> decodePaths = new ArrayList<>();
//此方法返回 可以处理data类型的解码器的处理结果的类型
//根据Glide初始化时的信息可知,返回值包含以下类型:
//BitmapDrawable,GifDrawable
List<Class<TResource>> registeredResourceClasses =
decoderRegistry.getResourceClasses(dataClass, resourceClass);
for (Class<TResource> registeredResourceClass : registeredResourceClasses) {
//若transcodeClass是registeredResourceClass的父类,则直接返回transcodeClass
//否则,根据Glide初始化时的信息可知,返回的是一个空List
//在此只有BitmapDrawable,会返回一个只包含Drawable的List。GifDrawable返回空List
List<Class<Transcode>> registeredTranscodeClasses =
transcoderRegistry.getTranscodeClasses(registeredResourceClass, transcodeClass);
for (Class<Transcode> registeredTranscodeClass : registeredTranscodeClasses) {
//获取可以将InputStream解码为BitmapDrawable的解码器
//解码器类型为InputStreamBitmapImageDecoderResourceDecoder,其在Glide初始化时被注册
List<ResourceDecoder<Data, TResource>> decoders =
decoderRegistry.getDecoders(dataClass, registeredResourceClass);
ResourceTranscoder<TResource, Transcode> transcoder =
transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass);
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
//将解码器封装到DecodePath中
DecodePath<Data, TResource, Transcode> path =
new DecodePath<>(
dataClass,
registeredResourceClass,
registeredTranscodeClass,
decoders,
transcoder,
throwableListPool);
decodePaths.add(path);
}
}
return decodePaths;
}
2)、使用图片解码器对输入流进行解码
在得到图片解码器之后,就可以调用runLoadPath方法对图片进行解码,此方法代码如下:
private <Data, ResourceType> Resource<R> runLoadPath(
Data data, DataSource dataSource, LoadPath<Data, ResourceType, R> path)
throws GlideException {
Options options = getOptionsWithHardwareConfig(dataSource);
//DataRewinder可能会对原始data进行处理,然后返回处理过的data,但是经过分析发现,
//此处的rewinder直接将原始data返回,并没有进行处理
DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
try {
return path.load(
rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
} finally {
rewinder.cleanup();
}
}
接下来会调用LoadPath的load方法解码图片输入流,此方法最后会调用DecodePath的decode方法,如下图所示:
public Resource<Transcode> decode(
DataRewinder<DataType> rewinder,
int width,
int height,
@NonNull Options options,
DecodeCallback<ResourceType> callback)
throws GlideException {
//将输入流解码为图片(BitmapDrawable)
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
//对图片进行变换和缓存处理
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
return transcoder.transcode(transformed, options);
}
可以看出,接下来会调用decodeResource方法对图片输入流进行解码,此方法代码如下:
private Resource<ResourceType> decodeResource(
DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options)
throws GlideException {
List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire());
try {
return decodeResourceWithList(rewinder, width, height, options, exceptions);
} finally {
listPool.release(exceptions);
}
}
接着decodeREsourceWithList方法,此方法代码如下:
private Resource<ResourceType> decodeResourceWithList(
DataRewinder<DataType> rewinder,
int width,
int height,
@NonNull Options options,
List<Throwable> exceptions)
throws GlideException {
Resource<ResourceType> result = null;
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = decoders.size(); i < size; i++) {
ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
try {
DataType data = rewinder.rewindAndGet();
if (decoder.handles(data, options)) {
//从rewinder中读取图片输入流data。rewinder前面已经简单介绍
data = rewinder.rewindAndGet();
//调用图片解码器将data转化为图片(BitmapDrawable)
result = decoder.decode(data, width, height, options);
}
// Some decoders throw unexpectedly. If they do, we shouldn't fail the entire load path, but
// instead log and continue. See #2406 for an example.
} catch (IOException | RuntimeException | OutOfMemoryError e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Failed to decode data for " + decoder, e);
}
exceptions.add(e);
}
......
}
......
return result;
}
此方法最终会调用InputStreamBitmapImageDecoderResourceDecoder的decode方法,对图片输入流进行解码,在此不再继续分析解码过程。
2.3、对图片进行变换及缓存处理
在将图片输入流解码为图片之后,调用DecodeJob(其实现了DecodeCallBack)的onResourceDecoded方法对图片进行变换和缓存处理。方法代码如下所示:
<Z> Resource<Z> onResourceDecoded(DataSource dataSource, @NonNull Resource<Z> decoded) {
@SuppressWarnings("unchecked")
Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
Transformation<Z> appliedTransformation = null;
Resource<Z> transformed = decoded;
if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
//图片变换处理
appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
transformed = appliedTransformation.transform(glideContext, decoded, width, height);
}
// TODO: Make this the responsibility of the Transformation.
if (!decoded.equals(transformed)) {
decoded.recycle();
}
......
Resource<Z> result = transformed;
boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey);
if (diskCacheStrategy.isResourceCacheable(
isFromAlternateCacheKey, dataSource, encodeStrategy)) {
if (encoder == null) {
throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass());
}
final Key key;
switch (encodeStrategy) {
case SOURCE:
key = new DataCacheKey(currentSourceKey, signature);
break;
case TRANSFORMED:
key =
new ResourceCacheKey(
decodeHelper.getArrayPool(),
currentSourceKey,
signature,
width,
height,
appliedTransformation,
resourceSubClass,
options);
break;
default:
throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy);
}
LockedResource<Z> lockedResult = LockedResource.obtain(transformed);
//图片缓存处理(目前只是将图片记录下来,后面会进行保存)
deferredEncodeManager.init(key, encoder, lockedResult);
result = lockedResult;
}
return result;
}
三、将图片回调至主线程并展示
3.1、图片回调至主线程
在DecodeJob完成对图片的处理之后,会调用notifyEncodeAndRelease方法,其代码如下:
private void notifyEncodeAndRelease(
Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
if (resource instanceof Initializable) {
((Initializable) resource).initialize();
}
......
notifyComplete(result, dataSource, isLoadedFromAlternateCacheKey);
stage = Stage.ENCODE;
try {
if (deferredEncodeManager.hasResourceToEncode()) {
//保存处理后的图片
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
......
}
notifyComplete方法代码如下:
private void notifyComplete(
Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
setNotifiedOrThrow();
//EngineJob实现了DecodeJob.Callback,并在之前进行了注册,
//所以会调用EngineJob的onResourceReady方法
callback.onResourceReady(resource, dataSource, isLoadedFromAlternateCacheKey);
}
EngineJob的onResourceReady方法代码如下:
public void onResourceReady(
Resource<R> resource, DataSource dataSource, boolean isLoadedFromAlternateCacheKey) {
synchronized (this) {
this.resource = resource; //resource中有加载到的图片
this.dataSource = dataSource;
this.isLoadedFromAlternateCacheKey = isLoadedFromAlternateCacheKey;
}
//此方法如下
notifyCallbacksOfResult();
}
void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKey;
EngineResource<?> localResource;
synchronized (this) {
stateVerifier.throwIfRecycled();
if (isCancelled) {
resource.recycle();
release();
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
} else if (hasResource) {
throw new IllegalStateException("Already have resource");
}
engineResource = engineResourceFactory.build(resource, isCacheable, key, resourceListener);
hasResource = true;
copy = cbs.copy();
incrementPendingCallbacks(copy.size() + 1);
localKey = key;
localResource = engineResource;
}
engineJobListener.onEngineJobComplete(this, localKey, localResource);
//发送到主线程处理图片
for (final ResourceCallbackAndExecutor entry : copy) {
//executor为之前构建Request时传入的主线程池
//cb为SingleRequest
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
CallResourceReady是一个Runnable对象,其会在主线程执行,它的run方法如下:
public void run() {
// Make sure we always acquire the request lock, then the EngineJob lock to avoid deadlock
// (b/136032534).
synchronized (cb.getLock()) {
synchronized (EngineJob.this) {
if (cbs.contains(cb)) {
// Acquire for this particular callback.
engineResource.acquire();
//处理图片
callCallbackOnResourceReady(cb);
removeCallback(cb);
}
decrementPendingCallbacks();
}
}
}
callCallbackOnResourceReady方法的代码如下:
void callCallbackOnResourceReady(ResourceCallback cb) {
try {
// cb为SingleRequest
cb.onResourceReady(engineResource, dataSource, isLoadedFromAlternateCacheKey);
} catch (Throwable t) {
throw new CallbackException(t);
}
}
onResourceReady方法的代码如下:
private void onResourceReady(
Resource<R> resource, R result, DataSource dataSource, boolean isAlternateCacheKey) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
......
isCallingCallbacks = true;
try {
boolean anyListenerHandledUpdatingTarget = false;
if (requestListeners != null) {
for (RequestListener<R> listener : requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onResourceReady(result, model, target, dataSource, isFirstResource);
}
}
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
//执行此方法,在UI上展示图片
//target为之前封装ImageView的ViewTarget
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
3.2、展示图片
在加载到图片之后,Glide会调用ViewTarget的onResourceReady方法,并将加载的图片传入。在前面介绍给,Glide的into方法会将ImageView封装到ViewTarget中,此ViewTarget的onResourceReady方法的代码如下:
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
setResourceInternal方法的代码如下:
private void setResourceInternal(@Nullable Z resource) {
// Order matters here. Set the resource first to make sure that the Drawable has a valid and
// non-null Callback before starting it.
setResource(resource);
maybeUpdateAnimatable(resource);
}
protected void setResource(@Nullable Drawable resource) {
//给ImageView设置图片
view.setImageDrawable(resource);
}
至此,Glide加载图片的大体过程就分析结束了。本文对一些较为细节的地方没有深入分析,如: 通过HTTPURLConnection获取图片输入流的具体过程,图片输入流编码为Bitmap的具体过程、图片的变换和缓存过程。之后将会继续完善上述部分。