Glide是什么?
Glide是一个Android的图片加载和缓存库,它主要专注于大量图片的流畅加载。是google所推荐的图片加载库,作者是bumptech。这个库被广泛运用在google的开源项目中,包括2014年的google I/O大会上发布的官方App。
WIKI地址: WIKI官网
Github地址: Github
1、多样化媒体加载
Glide 不仅是一个图片缓存,它支持 Gif、WebP等格式
2、生命周期集成
我们可以更加高效的使用Glide提供的方式进行绑定,这样可以更好的让加载图片的请求的生命周期动态管理起来
3、高效的缓存策略
4、 提供丰富的图片转换Api,支持圆形裁剪、平滑显示等特性
Glide怎么用?
1、gradle引入库,implementation 'com.github.bumptech.glide:glide:4.7.1'
2、配置Glide的with load apply into等方法
public void loadImageView(ImageView view,String url){
//属性的配置
RequestOptions options = new RequestOptions()
//加载成功之前占位图
.placeholder(R.mipmap.ic_launcher)
//加载错误之后的错误图
.error(R.mipmap.ic_launcher)
//指定图片的尺寸
.override(1000,800)
//指定图片的缩放类型为fitCenter (等比例缩放图片,宽或者是高等于ImageView的宽或者是高。)
.fitCenter()
//指定图片的缩放类型为centerCrop (等比例缩放图片,直到图片的狂高都大于等于ImageView的宽度,然后截取中间的显示。)
.centerCrop()
.circleCrop()//指定图片的缩放类型为centerCrop (圆形)
//跳过内存缓存
.skipMemoryCache(true)
//缓存所有版本的图像
.diskCacheStrategy(DiskCacheStrategy.ALL)
//跳过磁盘缓存
.diskCacheStrategy(DiskCacheStrategy.NONE)
//只缓存原来分辨率的图片
.diskCacheStrategy(DiskCacheStrategy.DATA)
//只缓存最终的图片
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.priority(Priority.HIGH)
//加载图片
Glide.with(getApplicationContext())
.load(url)
.apply(options)
.into(view);
复制代码
3、执行ImageView的加载
loadImageView(ivPic,"http://b.hiphotos.baidu.com/image/pic/item/d52a2834349b033bda94010519ce36d3d439bdd5.jpg");
复制代码
详细的使用教程及option的配置,推荐参考
Android图片加载框架最全解析(八),带你全面了解Glide 4的用法
Glide核心执行流程是怎样?
ResourceDecoder 数据解码器,比如ByteBufferGifDecoder(将ByteBuffer转换为Gif),StreamBitmapDecoder(Stream转换为Bitmap) ResourceTranscoder 资源转换器,将给定的资源类型,转换为另一种资源类型,比如将Bitmap转换为Drawable,Bitmap转换为Bytes Transformation 比如对图片进行FitCenter,CircleCrop,CenterCrop的transformation,或者根据给定宽高对Bitmap进行处理的BitmapDrawableTransformation Target request的载体,各种资源对应的加载类,含有生命周期的回调方法,方便开发人员进行相应的准备以及资源回收工作1、构建Request,实现类为SingleRequest,用于发起一个加载的请求
2、通过EngineJob和DecodeJob负责任务创建,发起,回调,资源的管理
3、根据请求的资源类型,最后匹配对应的DateFetcher进行Data数据的获取
4、获取数据进行相应的缓存配置
5、根据原始数据Data进行解码及转换,生成最终需要显示的Resource
6、通过回调Target对应的方法,最后进行图片的显示
关键类功能说明
Glide 向外暴露单例静态接口,构建Request,配置资源类型,缓存策略,图片处理等,可以直接通过该类完成简单的图片请求和填充。内部持有一些内存变量BitmapPool,MemoryCache,ByteArrayPool,便于低内存情况时自动清理内存 RequestManagerRetriever 用于创建RequestManager对象,并与Context做相应的生命周期绑定 RequestManagerFragment Glide向Activity或Fragment中添加的空Fragment,用于控制绑定生命周期 LifecycleListener 用于监听Activity或者Fragment的生命周期方法的接口 RequestManager 用户管理及发起请求,支持resume、pause、clear等操作 RequestBuilder 创建请求,资源类型配置,缩略图配置,以及通过BaseRequestOptions进行一些默认图,图片处理的配置 Engine 任务创建,发起,回调,管理存活和缓存的资源 EngineJob 调度DecodeJob,添加,移除资源回调,并notify回调 DecodeJob 实现了Runnable接口,调度任务的核心类,整个请求的繁重工作都在这里完成:处理来自缓存或者原始的资源,应用转换动画以及transcode。负责根据缓存类型获取不同的Generator加载数据,数据加载成功后回调DecodeJob的onDataFetcherReady方法对资源进行处理 ResourceCacheGenerator 尝试从修改过的资源缓存中获取,如果缓存未命中,尝试从DATA_CACHE中获取 DataCacheGenerator 尝试从未修改过的本地缓存中获取数据,如果缓存未命中则尝试从SourceGenerator中获取 SourceGenerator 从原始的资源中获取,可能是服务器,也可能是本地的一些原始资源 DataFetcher 数据加载接口,通过loadData加载数据并执行对应的回调 LoadPath 根据给定的数据类型的DataFetcher尝试获取数据,然后尝试通过一个或多个decodePath进行decode DecodePath 根据指定的数据类型对resource进行decode和transcode Registry 管理组件(数据类型+数据处理)的注册 ModelLoaderRegistry 注册所有数据加载的loader ResourceDecoderRegistry 注册所有资源转换的decoder TranscoderRegistry 注册所有对decoder之后进行特殊处理的transcoder ResourceEncoderRegistry 注册所有持久化resource(处理过的资源)数据的encoder EncoderRegistry 注册所有的持久化原始数据的encoder代码执行流程
先贴一下流程图,建议通过源码结合流程图进行分析,下面再分步骤进行分析。
下面主要从with()、load()、into()3个方法进行分析。
with()
1、with()方法,最后会返回一个RequestManger对象用于发起Request。
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
复制代码
2、getRetriever(context),最后返回一个RequestManagerRetriever对象用于生成RequestManager。
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
Preconditions.checkNotNull(
context,
"You cannot start a load on a not yet attached View or a Fragment where getActivity() "
+ "returns null (which usually occurs when getActivity() is called before the Fragment "
+ "is attached or after the Fragment is destroyed).");
return Glide.get(context).getRequestManagerRetriever();
复制代码
这里Glide.get(contenxt),会对glide进行初始化,模块扫描、组件注册等工作。
3、RequestManagerRetriever的get(context)方法
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
return getApplicationManager(context);
复制代码
这里主要根据context的类型,去创建不同的RequestManager的对象,绑定生命周期。 如果context是Application对象的话,则调用,绑定了ApplicationLifecycle。
private RequestManager getApplicationManager(@NonNull Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
// Normally pause/resume is taken care of by the fragment we add to the fragment or
// activity. However, in this case since the manager attached to the application will not
// receive lifecycle events, we must force the manager to start resumed using
// ApplicationLifecycle.
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
复制代码
4、如果context是Activity或Fragment的话,则会调用supportFragmentGet、FragmentGetd方法,创建RequestManagerFragment进行生命周期绑定ActivityFragmentLifecycle。
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
return requestManager;
复制代码
总结一下:with()方法,最后会返回一个根据context类型绑定生命周期的RequestManger对象。
load()
1.load()方法最后会生成一个RequestBuilder对象,用于构建Request,并执行请求操作.。首先会通过as方法生成一个RequestBuilder对象
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
复制代码
2、执行load()方法
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
复制代码
3、执行loadGeneric方法
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
复制代码
保存load传进行的参数,并设置isModelSet为true
4、设置请求的配置参数,apply(RequestOptions requestOptions)
public RequestBuilder<TranscodeType> apply(@NonNull RequestOptions requestOptions) {
Preconditions.checkNotNull(requestOptions);
this.requestOptions = getMutableOptions().apply(requestOptions);
return this;
复制代码
总结一下load()方法,最后会返回一个RequestBuilder对象,通过apply设置请求的参数,用于构建Request。
into()
into()是整个过程最复杂的一步,简单来说就是通过缓存策略及注册的Moderload,最终去加载源数据Data,并进行转换为配置的Resource,最后显示再Target上。
1、RequestBuilder的into方法实现
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
@NonNull RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
options = options.autoClone();
Request request = buildRequest(target, targetListener, options);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
return target;
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
复制代码
2、会执行BuildRequest()生成Request对象。经过一系列的调用,最后执行的方法如下,会返回一个SingleRequest对象实例
private Request obtainRequest(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
RequestOptions requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight) {
return SingleRequest.obtain(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListener,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory());
复制代码
3、接着会调用 requestManager.track(target, request);实现如下:
void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
复制代码
4、这里涉及到一个新类RequestTracker,用于管理Request的生命周期。runRequest实现如下:
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
pendingRequests.add(request);
复制代码
5、最后会调用Request的begin()方法开始执行请求,实现如下:
public void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
// Restarts for requests that are neither complete nor running can be treated as new requests
// and can run again from the beginning.
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
复制代码
这里主要会根据status进行判断,如果COMPLETE已完成,则直接回调 onResourceReady,如果是WAITING_FOR_SIZE,则会执行onSizeReady方法,我们都知道Glide会根据实际显示的View宽高去生成最后的Resource进行显示。
6、onResourceReady实现如下:
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
if (status != Status.WAITING_FOR_SIZE) {
return;
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (IS_VERBOSE_LOGGABLE) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
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);
// This is a hack that's only useful for testing right now where loads complete synchronously
// even though under any executor running on any thread but the main thread, the load would
// have completed asynchronously.
if (status != Status.RUNNING) {
loadStatus = null;
if (IS_VERBOSE_LOGGABLE) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
复制代码
最终会通过engine的load方法去执行请求,后续的缓存策略、数据加载、图片转换都是在下面步骤执行
7、具体看Engine的load方法实现
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb) {
Util.assertMainThread();
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
return null;
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
return null;
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
return new LoadStatus(cb, current);
EngineJob<R> engineJob =
engineJobFactory.build(
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
return new LoadStatus(cb, engineJob);
复制代码
这里首先通过构建EngineKey,判断内存缓存中是否命中。接着判断jobs队列中是否已存在该任务。否则会构建EngineJob、DecodeJob,并通过engineJob.start(decodeJob),通过线程池去执行DecodeJob任务。DecodeJob实现了Runnable接口,所以我们接着分析DecodeJob的run方法
8、DecodeJob的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);
复制代码
根据不同的runReason执行不同的任务,共两种任务类型:
runGenerators():load数据
decodeFromRetrievedData():处理已经load到的数据
RunReason再次执行任务的原因,三种枚举值: INITIALIZE:第一次调度任务
WITCH_TO_SOURCE_SERVICE:本地缓存策略失败,尝试重新获取数据,两种情况;当stage为Stage.SOURCE,或者获取数据失败并且执行和回调发生在了不同的线程
DECODE_DATA:获取数据成功,但执行和回调不在同一线程,希望回到自己的线程去处理数据。
9、getNextStage()是获取加载资源的策略,一共5种策略: INITIALIZE,RESOURCE_CACHE,DATA_CACHE,SOURCE,FINISHED
其中加载数据的策略有三种: RESOURCE_CACHE,DATA_CACHE,SOURCE, 分别对应的Generator:
ResourceCacheGenerator :尝试从修改过的资源缓存中获取,如果缓存未命中,尝试从DATA_CACHE中获取
DataCacheGenerator :尝试从未修改过的本地缓存中获取数据,如果缓存未命中则尝试从SourceGenerator中获取
SourceGenerator :从原始的资源中获取,可能是服务器,也可能是本地的一些原始资源 策略的配置在DiskCacheStrategy。开发者可通过BaseRequestOptions设置: RESOURCE AUTOMATIC(默认方式,依赖于DataFetcher的数据源和ResourceEncoder的EncodeStrategy)
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// Skip loading from source if the user opted to only retrieve the resource from cache.
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
复制代码
10、getNextGenerator,根据Stage获取到相应的Generator后会执行currentGenerator.startNext(),如果中途startNext返回true,则直接回调,否则最终会得到SOURCE的stage,重新调度任务。
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;
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
复制代码
11、这里我们分析最后SourceGenerator的startNext的执行,实现如下:
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
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;
复制代码
最后会通过Glide初始化时,Register注册的ModelLoader去执行对应的loadData方法,最后回调onDataFetcherReady(),获取得到DataSource,并将 runReason = RunReason.DECODE_DATA。触发调用decodeFromRetrievedData()进行源数据的转换
12、decodeFromRetrievedData,获取数据成功后,进行处理,内部调用的是runLoadPath(Data data, DataSource dataSource,LoadPath<Data, ResourceType, R> path),decode完成后的回调,对decode的资源进行transform。
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();
@SuppressWarnings("unchecked")
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
throws GlideException {
LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
return runLoadPath(data, dataSource, path);
复制代码
13、decodeFromRetrievedData()中,数据decode和transform后会执行notifyEncodeAndRelease方法,在该方法中调用 notifyComplete(result, dataSource),接着调用callback.onResourceReady,实现如下:
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
this.resource = resource;
this.dataSource = dataSource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
复制代码
14、通过Handler将回调切换到主线程, 最后调用EngineJob的handleResultOnMainThread方法,实现如下:
void handleResultOnMainThread() {
stateVerifier.throwIfRecycled();
if (isCancelled) {
resource.recycle();
release(false /*isRemovedFromQueue*/);
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);
hasResource = true;
// Hold on to resource for duration of request so we don't recycle it in the middle of
// notifying if it synchronously released by one of the callbacks.
engineResource.acquire();
listener.onEngineJobComplete(this, key, engineResource);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = cbs.size(); i < size; i++) {
ResourceCallback cb = cbs.get(i);
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource, dataSource);
// Our request is complete, so we can release the resource.
engineResource.release();
release(false /*isRemovedFromQueue*/);
复制代码
15、进行相关的资源清理后,最后调用SingleRequest的onResourceReady(Resource<?> resource, DataSource dataSource) 方法,最后调用target.onResourceReady(result, animation)方法,实现资源的显示,代码如下:
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
if (glideContext.getLogLevel() <= Log.DEBUG) {
Log.d(GLIDE_TAG, "Finished loading " + result.getClass().getSimpleName() + " from "
+ dataSource + " for " + model + " with size [" + width + "x" + height + "] in "
+ LogTime.getElapsedMillis(startTime) + " ms");
isCallingCallbacks = true;
try {
if ((requestListener == null
|| !requestListener.onResourceReady(result, model, target, dataSource, isFirstResource))
&& (targetListener == null
|| !targetListener.onResourceReady(result, model, target, dataSource, isFirstResource))) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
target.onResourceReady(result, animation);
} finally {
isCallingCallbacks = false;
notifyLoadSuccess();
复制代码
Glide是如何与Activity及Fragment等的生命周期绑定?
Glide在执行with的阶段,会根据context的类型,将Glide的Request请求与context类型进行绑定。Application类型为整个应用的生命周期。Fragment及Activity类型,通过巧妙的设计一个RequestManagerFragment,加入到Activity或Fragment当中,从而实现生命周期的监听。
1、Application的绑定为ApplicationLifecycle,与App的生命周期一致
@Override
public void addListener(@NonNull LifecycleListener listener) {
listener.onStart();
@Override
public void removeListener(@NonNull LifecycleListener listener) {
// Do nothing.
复制代码
2、Activity或Fragment的绑定为ActivityFragmentLifecycle,与宿主对应的生命周期一致。
public interface LifecycleListener {
* Callback for when {@link android.app.Fragment#onStart()}} or {@link
* android.app.Activity#onStart()} is called.
void onStart();
* Callback for when {@link android.app.Fragment#onStop()}} or {@link
* android.app.Activity#onStop()}} is called.
void onStop();
* Callback for when {@link android.app.Fragment#onDestroy()}} or {@link
* android.app.Activity#onDestroy()} is called.
void onDestroy();
复制代码
3、在RequestManger中实现了监听接口的注册,代码如下:
private final Runnable addSelfToLifecycle = new Runnable() {
@Override
public void run() {
lifecycle.addListener(RequestManager.this);
复制代码
这里注意,一个页面拥有一个RequestManagerFragment,RequestManagerFragment会持有RequestManger的引用。一个页面发起多个Glide显示图片请求,会优先从Fragment中获取RequestManger,不会重复创建多个RequestManger对象。
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
return requestManager;
复制代码
4、RequestManger中绑定的回调执行
* Lifecycle callback that registers for connectivity events (if the * android.permission.ACCESS_NETWORK_STATE permission is present) and restarts failed or paused * requests. @Override public void onStart() { resumeRequests (); targetTracker .onStart (); * Lifecycle callback that unregisters for connectivity events (if the * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads. @Override public void onStop() { pauseRequests (); targetTracker .onStop (); * Lifecycle callback that cancels all in progress requests and clears and recycles resources for * all completed requests. @Override public void onDestroy() { targetTracker .onDestroy (); for (Target<?> target : targetTracker.getAll()) { clear (target); targetTracker .clear (); requestTracker .clearRequests (); lifecycle .removeListener (this); lifecycle .removeListener (connectivityMonitor); mainHandler .removeCallbacks (addSelfToLifecycle); glide .unregisterRequestManager (this); 复制代码从实现可知,当Activity或Fragment退到后台时,会调用pauseRequests()暂停请求,回到前台时会重新执行请求,当页面销毁时,会进行对应的资源清理及回收。
Glide的缓存实现原理是怎样的?
Glide的缓存使用内存缓存及硬盘缓存进行处理。
假如用户配置了使用内存缓存及磁盘缓存,则主要的加载实现流程如下:
1、当发起Request时,首先会从ActiveResources中进行缓存查找。如果命中则返回显示,如果不命中,则从MemoryCache中获取。当资源从ActiveResources中移除后,加入到MemoryCache中
2、当在MemoryCache中命中时,则会将资源加入到ActiveResources中,并在该Cache中移除,如果不命中则会尝试从磁盘缓存中进行加载
3、根据用于配置的策略,如果在磁盘缓存中命中,则会返回,并将资源缓存到ActiveResources当中,如果不命中,则会将进行网络的请求
4、根据ModelLoader的配置实现,从网络中加载资源,并根据配置,缓存到磁盘及内存缓存中
根据流程分析,我们知道Key的生成在Engine的load方法中,具体的实现如下:
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
复制代码
可见为了兼容复杂的资源转换,保证key的唯一性,包含了非常多的参数进行构建。主要有model(目标地址)、signature(设置的签名)、图片的width、heigh、资源的转换配置等。
根据上面的简介,我们可以知道,Glide主要的内存缓存策略采用了2级缓存,为ActiveResources和MemoryCache。下面我们从源码的角度分析这2个缓存的机制。
ActiveResources
1、 根据源码,我们可知内存采用了一个HashMap进行内存的缓存,使用了弱引用ResourceWeakReference持有了Resource
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
复制代码
2、当获取资源时,主要采用get方法进行获取,实现如下:
EngineResource<?> get(Key key) {
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
return null;
EngineResource<?> active = activeRef.get();
if (active == null) {
cleanupActiveReference(activeRef);
return active;
复制代码
如果命中,就返回资源。这里注意,如果当active==null,引用被回收时,会调用cleanupActiveReference方法,实现如下:
void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
Util.assertMainThread();
activeEngineResources.remove(ref.key);
if (!ref.isCacheable || ref.resource == null) {
return;
EngineResource<?> newResource =
new EngineResource<>(ref.resource, /*isCacheable=*/ true, /*isRecyclable=*/ false);
newResource.setResourceListener(ref.key, listener);
listener.onResourceReleased(ref.key, newResource);
复制代码
如果ref.resource!=null,则会重新生成一个EngineResource对象,并回调onResourceReleased方法,我们看具体的实现如下:
@Override
public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
Util.assertMainThread();
activeResources.deactivate(cacheKey);
if (resource.isCacheable()) {
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
复制代码
从源码可知,会调用deactivate方法,从activeResources中移除,然后加入到MemoryCache中。
3、写入资源
void activate(Key key, EngineResource<?> resource) {
ResourceWeakReference toPut =
new ResourceWeakReference(
resource,
getReferenceQueue(),
isActiveResourceRetentionAllowed);
ResourceWeakReference removed = activeEngineResources.put(key, toPut);
if (removed != null) {
removed.reset();
复制代码
EngineResource
EngineResource中主要为了一个acquired变量
private int acquired;
复制代码
当资源被使用时,会调用acquire,将变量值+1
void acquire() {
if (isRecycled) {
throw new IllegalStateException("Cannot acquire a recycled resource");
if (!Looper.getMainLooper().equals(Looper.myLooper())) {
throw new IllegalThreadStateException("Must call acquire on the main thread");
++acquired;
复制代码
当资源被释放时,会调用release()方法
void release() {
if (acquired <= 0) {
throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
if (!Looper.getMainLooper().equals(Looper.myLooper())) {
throw new IllegalThreadStateException("Must call release on the main thread");
if (--acquired == 0) {
listener.onResourceReleased(key, this);
复制代码
这里注意,当acquired == 0,表明资源没有被使用时,则会调用onResourceReleased,将资源存储到MemoryCache中。这样也就实现了正在使用中的图片使用弱引用来进行缓存,不在使用中的图片使用LruCache来进行缓存的功能。
MemoryCache
Glide在Build的过程中会创建具体的MemoryCache对象,具体的实现如下:
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
复制代码
从源码可知,MemoryCache的主要实现是采用了LRU算法,我们具体查看LruResourceCache的实现。发现其继承与LruCache,LruCache的关键实现如下:
private final Map<T, Y> cache = new LinkedHashMap<>(100, 0.75f, true);
复制代码
从源码可知,Glide的内存缓存的LRU算法实现主要是使用了LinkedHashMap。
这里详细的说明可参考: 如何用LinkedHashMap实现LRU缓存算法
BitmapPool
Glide内部维护了一个BitmapPool池,用于Bitmap的复用,可优化GC的回收。 在GlideBuilder中进行了实例,实现如下:
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
复制代码
我们具体看LruBitmapPool的实现代码
1、 put
@Override
public synchronized void put(Bitmap bitmap) {
if (bitmap == null) {
throw new NullPointerException("Bitmap must not be null");
if (bitmap.isRecycled()) {
throw new IllegalStateException("Cannot pool recycled bitmap");
if (!bitmap.isMutable() || strategy.getSize(bitmap) > maxSize
|| !allowedConfigs.contains(bitmap.getConfig())) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Reject bitmap from pool"
+ ", bitmap: " + strategy.logBitmap(bitmap)
+ ", is mutable: " + bitmap.isMutable()
+ ", is allowed config: " + allowedConfigs.contains(bitmap.getConfig()));
bitmap.recycle();
return;
final int size = strategy.getSize(bitmap);
strategy.put(bitmap);
tracker.add(bitmap);
puts++;
currentSize += size;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Put bitmap in pool=" + strategy.logBitmap(bitmap));
dump();
evict();
复制代码
做了一系列的非空、回收判断后,最后将bitmap加入到strategy中,加入到缓存中
2、get
@Override
@NonNull
public Bitmap get(int width, int height, Bitmap.Config config) {
Bitmap result = getDirtyOrNull(width, height, config);
if (result != null) {
// Bitmaps in the pool contain random data that in some cases must be cleared for an image
// to be rendered correctly. we shouldn't force all consumers to independently erase the
// contents individually, so we do so here. See issue #131.
result.eraseColor(Color.TRANSPARENT);
} else {
result = createBitmap(width, height, config);
return result;
复制代码
当需要生成Bitmap中,根据宽高及config从池中获取,如果没有,则调用createBtimao创建一个。如果命中,则会提取出Bitmap,然后将像素都设置为透明,同时从池中移除,并返回。
glide采用了2级的内存缓存,activeResources是一个以弱引用资源为value,的map,memory是使用LruResourceCache实现的。就是activeResources是一个随时有可能被回收资源。它存在的意义在于,memory的强引用的频繁读写也有可能造成内存激增频繁GC,而造成内存抖动。资源在使用的过程中将会保存在activeResources中,而activeResources是弱引用的,可以随时被系统回收,不会造成内存泄漏和过多的使用
Glide缓存的资源分为两种(1,原图(SOURCE)原始图片 2,处理图(RESULT)经过压缩和变形等转化的图片)
硬盘缓存分为五种,具体看一面。可以通过调用diskCacheStrategy()方法并传入五种不同的参数
1,DiskCacheStrategy.NONE// 表示不缓存任何内容
2,DiskCacheStrategy.DATA// 表示只缓存原始图片
3,DiskCacheStrategy.RESOURCE// 表示只缓存转换过后的图片
4,DiskCacheStrategy.ALL // 表示既缓存原始图片,也缓存转换过后的图片
5,DiskCacheStrategy.AUTOMATIC//表示让Glide根据图片资源智能地选择使用哪一种缓存策略(默认选项)
缓存的获取
1、根据上述的流程分析,我们知道具体磁盘缓存在DecodeJob中执行,当任务开始时,调用了runWrapped()方法,接着会调用getNextStage,这里会获取磁盘的加载策略Stage,具体实现如下:
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// Skip loading from source if the user opted to only retrieve the resource from cache.
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
复制代码
接着会调用getNextGenerator方法,实现如下:
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);
复制代码
这里获取下一步执行的策略,一共5种策略: INITIALIZE,RESOURCE_CACHE,DATA_CACHE,SOURCE,FINISHED
其中加载数据的策略有三种: RESOURCE_CACHE,DATA_CACHE,SOURCE, 分别对应的Generator:
ResourceCacheGenerator :尝试从修改过的资源缓存中获取,如果缓存未命中,尝试从DATA_CACHE中获取
DataCacheGenerator :尝试从未修改过的本地缓存中获取数据,如果缓存未命中则尝试从SourceGenerator中获取
SourceGenerator :从原始的资源中获取,可能是服务器,也可能是本地的一些原始资源
接着调用具体的Generator的startNext方法。磁盘的缓存获取实现在这个方法中获取。 这里ResourceCacheGenerator的关键缓存获取代码如下:
Key sourceId = sourceIds.get(sourceIdIndex);
Class<?> resourceClass = resourceClasses.get(resourceClassIndex);
Transformation<?> transformation = helper.getTransformation(resourceClass);
// PMD.AvoidInstantiatingObjectsInLoops Each iteration is comparatively expensive anyway,
// we only run until the first one succeeds, the loop runs for only a limited
// number of iterations on the order of 10-20 in the worst case.
currentKey =
new ResourceCacheKey(// NOPMD AvoidInstantiatingObjectsInLoops
helper.getArrayPool(),
sourceId,
helper.getSignature(),
helper.getWidth(),
helper.getHeight(),
transformation,
resourceClass,
helper.getOptions());
cacheFile = helper.getDiskCache().get(currentKey);
if (cacheFile != null) {
sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
复制代码
DataCacheGenerator的关键缓存获取代码如下:
Key sourceId = cacheKeys.get(sourceIdIndex);
// PMD.AvoidInstantiatingObjectsInLoops The loop iterates a limited number of times
// and the actions it performs are much more expensive than a single allocation.
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
cacheFile = helper.getDiskCache().get(originalKey);
if (cacheFile != null) {
this.sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
复制代码
缓存的写入
1、Data数据的缓存
从服务端获取数据的主要实现在SourceGenerator中,我们查看源码onDataReady可知其中判断了isDataCacheable()会将数据赋值到dataToCache中。重新触发reschedule();
@Override
public void onDataReady(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 {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
复制代码
当再次出发startNext,关键实现如下:
@Override
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
复制代码
其中的cacheData,将原始的Data数据缓存到磁盘文件中,代码实现如下:
private void cacheData(Object dataToCache) {
long startTime = LogTime.getLogTime();
try {
Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
DataCacheWriter<Object> writer =
new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
helper.getDiskCache().put(originalKey, writer);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished encoding source to cache"
+ ", key: " + originalKey
+ ", data: " + dataToCache
+ ", encoder: " + encoder
+ ", duration: " + LogTime.getElapsedMillis(startTime));
} finally {
loadData.fetcher.cleanup();
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
复制代码
2、Resource数据的缓存
根据上述的流程分析,再DecodeJob中的onResourceDecoded回调中,关键的实现如下:
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;
复制代码
会初始化DeferredEncodeManager对象。接着会执行到notifyEncodeAndRelease()方法,其中关键的实现如下:
try {
if (deferredEncodeManager.hasResourceToEncode()) {
deferredEncodeManager.encode(diskCacheProvider, options);
} finally {
if (lockedResource != null) {
lockedResource.unlock();
复制代码
在encode中进行了resource数据的缓存,代码如下:
void encode(DiskCacheProvider diskCacheProvider, Options options) {
GlideTrace.beginSection("DecodeJob.encode");
try {
diskCacheProvider.getDiskCache().put(key,
new DataCacheWriter<>(encoder, toEncode, options));
} finally {
toEncode.unlock();
GlideTrace.endSection();
复制代码
缓存的实现
1、在Glide的Build方法中,我们可以看到磁盘缓存的工厂实例,代码如下:
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
复制代码
2、InternalCacheDiskCacheFactory继承了DiskLruCacheFactory,工厂关键的build方法如下:
@Override
public DiskCache build() {
File cacheDir = cacheDirectoryGetter.getCacheDirectory();
if (cacheDir == null) {
return null;
if (!cacheDir.mkdirs() && (!cacheDir.exists() || !cacheDir.isDirectory())) {
return null;
return DiskLruCacheWrapper.create(cacheDir, diskCacheSize);
复制代码
3、可见实际的磁盘缓存对象为DiskLruCacheWrapper类,我们看对应的get、put方法,实现如下:
@Override
public File get(Key key) {
String safeKey = safeKeyGenerator.getSafeKey(key);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Get: Obtained: " + safeKey + " for for Key: " + key);
File result = null;
try {
// It is possible that the there will be a put in between these two gets. If so that shouldn't
// be a problem because we will always put the same value at the same key so our input streams
// will still represent the same data.
final DiskLruCache.Value value = getDiskCache().get(safeKey);
if (value != null) {
result = value.getFile(0);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to get from disk cache", e);
return result;
@Override
public void put(Key key, Writer writer) {
// We want to make sure that puts block so that data is available when put completes. We may
// actually not write any data if we find that data is written by the time we acquire the lock.
String safeKey = safeKeyGenerator.getSafeKey(key);
writeLocker.acquire(safeKey);
try {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Put: Obtained: " + safeKey + " for for Key: " + key);
try {
// We assume we only need to put once, so if data was written while we were trying to get
// the lock, we can simply abort.
DiskLruCache diskCache = getDiskCache();
Value current = diskCache.get(safeKey);
if (current != null) {
return;
DiskLruCache.Editor editor = diskCache.edit(safeKey);
if (editor == null) {
throw new IllegalStateException("Had two simultaneous puts for: " + safeKey);
try {
File file = editor.getFile(0);
if (writer.write(file)) {
editor.commit();
} finally {
editor.abortUnlessCommitted();
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to put to disk cache", e);
} finally {
writeLocker.release(safeKey);
复制代码
4、最终可知磁盘缓存的实现为DiskLruCache,关于DiskLruCache缓存可参考如下博文
Glide的底层网络实现是什么?
通过上述的流程分析,我们可知最后的网络加载在SourceGenerator中的startNext()方法,通过初始注册的ModelLoader对应的DataFetcher去加载数据。我们以load一个GlideUrl地址来分析
在Glide的构造函数中,Register会注册ModelLoader,代码实现如下:
.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
复制代码
在SourceGenerator中的startNext()方法中会循环匹配出对应的ModelLoader,实现如下:
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);
复制代码
我们查看HttpGlideUrlLoader,其最后的LoadData实现为HttpUrlFetcher,具体代码如下:
@Override
public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
@NonNull Options options) {
// GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
// spent parsing urls.
GlideUrl url = model;
if (modelCache != null) {
url = modelCache.get(model, 0, 0);
if (url == null) {
modelCache.put(model, 0, 0, model);
url = model;
int timeout = options.get(TIMEOUT);
return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
复制代码
HttpUrlFetcher具体加载网络的数据的实现如下:
@Override
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) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
Map<String, String> headers) throws IOException {
if (redirects >= MAXIMUM_REDIRECTS) {
throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
// Comparing the URLs using .equals performs additional network I/O and is generally broken.
// See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new HttpException("In re-direct loop");
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
urlConnection.setConnectTimeout(timeout);
urlConnection.setReadTimeout(timeout);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
// Stop the urlConnection instance of HttpUrlConnection from following redirects so that
// redirects will be handled by recursive calls to this method, loadDataWithRedirects.
urlConnection.setInstanceFollowRedirects(false);
// Connect explicitly to avoid errors in decoders if connection fails.
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);
} else if (isHttpRedirect(statusCode)) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new HttpException("Received empty or null redirect url");
URL redirectUrl = new URL(url, redirectUrlString);
// Closing the stream specifically is required to avoid leaking ResponseBodys in addition
// to disconnecting the url connection below. See #2352.
cleanup();
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else if (statusCode == INVALID_STATUS_CODE) {
throw new HttpException(statusCode);
} else {
throw new HttpException(urlConnection.getResponseMessage(), statusCode);
复制代码
通过分析可知,Glide默认的网络加载使用的是urlConnection。当然我们也可以通过自定义ModelLoader,使用okhttp、volley等的网络框架进行加载。
具体可参考博文 Glide 4.x添加自定义组件原理
Glide中代码运用了那些设计模式,有什么巧妙的设计?
1、建造者模式
Glide对象的创建使用Build模式,将复杂对象的创建和表示分离,调用者不需要知道复杂的创建过程,使用Build的相关方法进行配置创建对象。
2、外观模式
Glide对外提供了统一的调度,屏蔽了内部的实现,使得使用该网络库简单便捷。
3、策略模式
关于DecodeJob中的DataFetcherGenerator资源获取,采用了策略模式,将数据加载的不同算法进行封装。
4、工厂模式
ModelLoader的创建使用了ModelLoaderFactory、Engine中的EngineJobFactory、DiskLruCacheFactory等
Glide正因为其强大的功能,高效的运行机制,所以源码的实现非常复杂。在学习的过程中也遇到很多的困难,最终还是一步一步坚持下来了。有时候放弃就是一瞬间的念头,但坚持下来,终究会有收获。
Android图片加载框架最全解析(八),带你全面了解Glide 4的用法
欢迎关注我的个人公众号
微信搜索: 一码一浮生 ,或者搜索公众号ID: life2code