Glide图片加载框架原理

什么是Glide

Glide是一个快速高效的图片加载库(Android),性能高,流式API的语法特点。

特点

  • 1.可配置高,自适应度高;
  • 2.支持多种数据源,本地,网络,assets,gif再glide中都是支持的;
  • 3.高效缓存,支持memory和disk图片缓存,默认使用二级缓存;
  • 4.具有和AF同步的生命周期;
  • 5.高效处理Bitmap:使用Bitmap pool复用Bitmap,享元设计模式;
  • 6.图片接在过程可以监听。

    性能

    Glide 充分考虑了Android图片加载性能的两个关键方面:
  • 图片解码速度
  • 解码图片带来的资源压力
    为了让用户拥有良好的App使用体验,图片不仅要快速加载,而且还不能因为过多的主线程I/O或频繁的垃圾回收导致页面的闪烁和抖动现象。

Glide使用了多个步骤来确保在Android上加载图片尽可能的快速和平滑:

  • 自动、智能地下采样(downsampling)和缓存(caching),以最小化存储开销和解码次数;
  • 积极的资源重用,例如字节数组和Bitmap,以最小化昂贵的垃圾回收和堆碎片影响;
  • 深度的生命周期集成,以确保仅优先处理活跃的Fragment和Activity的请求,并有利于应用在必要时释放资源以避免在后台时被杀掉。

    架构

    图片请求,是发送到一个队列里,然后多个线程进行消费。如下图:

    使用

    依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    repositories {
    google()
    mavenCentral()
    }

    dependencies {
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    }

加载

this是imageview绑定的生命周期对象(Activity或Fragment)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
RequestOptions requestOptions = new RequestOptions();
Glide.with(this)
.load("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0")
.addListener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}

@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
})
.centerCrop()
.placeholder(R.drawable.ic_launcher_background)
.error(R.drawable.ic_launcher_foreground)
.override(100,100)
.apply(requestOptions)
.into(img);

override,默认使用xml设置,如果这里设置,就使用override设置大小。也可以通过RequestOptions设置。

取消加载:

1
Glide.with(this).clear(imageView);

尽管及时取消不必要的加载是很好的实践,但这并不是必须的操作。实际上,当 Glide.with() 中传入的 Activity 或 Fragment 实例销毁时,Glide 会自动取消加载并回收资源。

过度

再加载图片过程中,可以定义glide如何从占位到新加载的图片,或从缩略图到全尺寸图像的过度。再这些过程中,可以设置过渡动画。Glide默认实现了交叉淡入效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DrawableCrossFadeFactory fadeFactory = new DrawableCrossFadeFactory.Builder().setCrossFadeEnabled(true).build();

Glide.with(this)
.transition(DrawableTransitionOptions.with(fadeFactory))
.into(img);


Glide.with(this)
.transition(DrawableTransitionOptions.with(3000))
.into(img);


Glide.with(this).asBitmap()
.transition(BitmapTransitionOptions.with(3000))
.into(img);

不幸的是,虽然禁用交叉淡入通常是一个比较好的默认行为,当待加载的图片包含透明像素时仍然可能造成问题。当占位符比实际加载的图片要大,或者图片部分为透明时,禁用交叉淡入会导致动画完成后占位符在图片后面仍然可见。如果你在加载透明图片时使用了占位符,你可以启用交叉淡入,具体办法是调整 DrawableCrossFadeFactory 里的参数并将结果传到 transition() 中:
为了提升性能,请在使用 Glide 向 ListView , GridView, 或 RecyclerView 加载图片时考虑避免使用动画,尤其是大多数情况下,你希望图片被尽快缓存和加载的时候。

变换

在Glide中,Transformations 可以获取资源并修改它,然后返回被修改后的资源。通常变换操作是用来完成剪裁或对位图应用过滤器,但它也可以用于转换GIF动画,甚至自定义的资源类型。
Glide 提供了很多内置的变换,包括:

  • CenterCrop
  • FitCenter
  • CircleCrop
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Glide.with(fragment)
    .load(url)
    .fitCenter()
    .into(imageView);

    或使用 RequestOptions :

    RequestOptions options = new RequestOptions();
    options.centerCrop();

    Glide.with(fragment)
    .load(url)
    .apply(options)
    .into(imageView);

这里的变换指的是多重变换:默认情况下,每个 transform() 调用,或任何特定转换方法(fitCenter(), centerCrop(), bitmapTransform() etc)的调用都会替换掉之前的变换。
如果你想在单次加载中应用多个变换,请使用 MultiTransformation 类,或其快捷方法 .transforms() 。
比如:

  • 1.CircleCrop:圆角
  • 2.RoundedCorners:内个叫统一指定
  • 3.GranularRoundedCorners:四个角单独指定
  • 4.Rotate:旋转
    看下图效果:

    其他效果,自行调试。
    其中变换还有定制变换,重用变变换,具体自行看文档。

    Generated API

    添加 Glide 注解处理器的依赖:
    1
    2
    3
    dependencies {
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    }

在 Application 模块中包含一个 AppGlideModule 的实现:

1
2
3
4
5
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;

@GlideModule
public final class MyAppGlideModule extends AppGlideModule {}

Generated API 默认名为 GlideApp ,与 Application 模块中 AppGlideModule的子类包名相同。在 Application 模块中将 Glide.with() 替换为 GlideApp.with(),即可使用该 API 去完成加载工作:

1
2
3
4
5
6
7
8
9
GlideApp.with(fragment)
.load(myUrl)
.placeholder(R.drawable.placeholder)
.fitCenter()
.into(imageView);
```
与 Glide.with() 不同,诸如 fitCenter() 和 placeholder() 等选项在 Builder 中直接可用,并不需要再传入单独的 RequestOptions 对象。
### GlideExtension & GlideOption
Option扩展类,可以自定义实现选项配置。使用Glide更加简单。**变换效果不能配置**

@GlideExtension
public class MyAppExtension {
// Size of mini thumb in pixels.
private static final int MINI_THUMB_SIZE = 100;

private MyAppExtension() { } // utility class

//静态方法,BaseRequestOptions的扩展,封装了一些options的配置方法。
@NonNull
@GlideOption
public static BaseRequestOptions miniThumb(BaseRequestOptions options) {
return options
.fitCenter()
.override(MINI_THUMB_SIZE);
}

1
之后你就可以使用生成的 GlideApp 类调用你的自定义方法:

GlideApp.with(fragment)
.load(url)
.miniThumb(thumbnailSize)
.into(imageView);

1
2
3
4
5
6
7
## 源码分析

根据Glide分成三条主线:

### with

with返回的是RequestManager对象

public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}

1
最总会进入这个方法:这里会给Glide添加生命周期。

@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
//如果不是主线程,则没有生命周期
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
//主线程,添加了一个空白的Fragment,通过空白的Fragment监听this的生命周期。
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, /parentHint=/ null, isActivityVisible(activity));
}
}

private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}

1
2

同时,Glide再构造对象时,会顶一个registry,这个对象会append多种设置:

registry
.append(Uri.class, InputStream.class, new UriLoader.StreamFactory(contentResolver))
.append(
Uri.class,
ParcelFileDescriptor.class,
new UriLoader.FileDescriptorFactory(contentResolver))
.append(
Uri.class,
AssetFileDescriptor.class,
new UriLoader.AssetFileDescriptorFactory(contentResolver))
.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))
.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
.append(byte[].class, ByteBuffer.class, new ByteArrayLoader.ByteBufferFactory())
.append(byte[].class, InputStream.class, new ByteArrayLoader.StreamFactory())
.append(Uri.class, Uri.class, UnitModelLoader.Factory.getInstance())
.append(Drawable.class, Drawable.class, UnitModelLoader.Factory.getInstance())
.append(Drawable.class, Drawable.class, new UnitDrawableDecoder())
/* Transcoders */
.register(Bitmap.class, BitmapDrawable.class, new BitmapDrawableTranscoder(resources))
.register(Bitmap.class, byte[].class, bitmapBytesTranscoder)
.register(
Drawable.class,
byte[].class,
new DrawableBytesTranscoder(
bitmapPool, bitmapBytesTranscoder, gifDrawableBytesTranscoder))
.register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);

1
2
3
4

### load

load是指定url,返回的RequestBuilder对象,

public RequestBuilder load(@Nullable String string) {
return asDrawable().load(string);
}

private RequestBuilder loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}

1
2
3
4
5
6

### into

into,是重点啊,这个图片的显示,都在这个执行流程里:
RequestBuilder.into -> buildRequest ->
RequestManager.track -> RequestTracker.runRequest -> SingleRequest.begin -> onSizeReady -> Engile.load -> loadFromMemory ->waitForExistingOrStartNewJob -> EngineJob.build -> DecodeJob.build -> run -> runWrapped > runGenerators -> SourceGenerator.startNext -> DecodeHelper.getLoadData -> HttpGlideUrlLoader.buildLoadData -> HttpUrlFetcher.loadData > loadDataWithRedirects

@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);

BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don’t retain the transformation applied based on the previous
// View’s scale type.
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}

return into(
//得到ImageViewTarget
glideContext.buildImageViewTarget(view, transcodeClass),
/targetListener=/ null,
requestOptions,
Executors.mainThreadExecutor());
}

private <Y extends Target> Y into(
@NonNull Y target,
@Nullable RequestListener targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
。。。。。。。。。。。。。。。。。。
// 构建一个请求,实现类SingleRequest
Request request = buildRequest(target, targetListener, options, callbackExecutor);

Request previous = target.getRequest();
//如果上一个请求没有请求完
if (request.isEquivalentTo(previous)
    && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
    if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
    }
    return target;
}

requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;

}

1
RequestTracker:

//正在运行的队列
private final Set requests =
Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
//等待中的队列
private final List pendingRequests = new ArrayList<>();

public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, “Paused, delaying request”);
}
pendingRequests.add(request);
}
}

1
SingleRequest.begin:

@Override
public void begin() {
synchronized (requestLock) {
。。。。。。。。。。。。
//正在执行,直接返回异常
if (status == Status.RUNNING) {
throw new IllegalArgumentException(“Cannot restart a running request”);
}

if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}

status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
    onSizeReady(overrideWidth, overrideHeight);
} else {
    target.getSize(this);
}

…………………………………
}
// 传进宽高
public void onSizeReady(int width, int height) {
synchronized (requestLock) {
………………………………..
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);
}
}

1
Engine.load

public LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class resourceClass, Class transcodeClass, Priority priority, DiskCacheStrategy diskCacheStrategy, Map, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

//生成的 key 会用于缓存
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);
    }
}
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;

}

1
loadFromMemory从缓存取,也称运行时缓存(如果app被kill掉,就没有了):

private EngineResource loadFromMemory( EngineKey key, boolean isMemoryCacheable, long startTime) { if (!isMemoryCacheable) { return null; } // 先从活动缓存(用户正在显示的图片)拿,一级缓存 EngineResource active = loadFromActiveResources(key);
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey(“Loaded resource from active resources”, startTime, key);
}
return active;
}
// 再从内存缓存(活动缓存回收后给到内存缓存)拿,二级缓存
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey(“Loaded resource from cache”, startTime, key);
}
return cached;
}

return null;

}

1
waitForExistingOrStartNewJob:缓存中没有

private LoadStatus waitForExistingOrStartNewJob(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class resourceClass, Class transcodeClass, Priority priority, DiskCacheStrategy diskCacheStrategy, Map, Transformation> transformations, boolean isTransformationRequired, boolean isScaleOnlyOrNoTransform, Options options, boolean isMemoryCacheable, boolean useUnlimitedSourceExecutorPool, boolean useAnimationPool, boolean onlyRetrieveFromCache, ResourceCallback cb, Executor callbackExecutor, EngineKey key, long startTime) { //根据key拿当前正在运行中,有没有缓存(这里指磁盘缓存)可用,再验证一次缓存 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 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);
//把decodeJob,添加给引擎job,然后开始执行.
engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);

}

1
2
EngineJob,引擎Job,这里会由很多的线程池Executor,用来执行操作的:
DecodeJob,是一个任务,runnable.

private final StateVerifier stateVerifier = StateVerifier.newInstance();
private final ResourceListener resourceListener;
private final Pools.Pool<EngineJob<?>> pool;
private final EngineResourceFactory engineResourceFactory;
private final EngineJobListener engineJobListener;
private final GlideExecutor diskCacheExecutor;
private final GlideExecutor sourceExecutor;
private final GlideExecutor sourceUnlimitedExecutor;
private final GlideExecutor animationExecutor;
private final AtomicInteger pendingCallbacks = new AtomicInteger();

public synchronized void start(DecodeJob decodeJob) {
this.decodeJob = decodeJob;
//线程池
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
//执行runnable
executor.execute(decodeJob);
}

1
DecodeJob.run > runWrapped > runGenerators

public void run() {
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (CallbackException e) {
}
}

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);
}
}
//如果你配置了缓存策略,就使用,如果没有,就使用默认SOURCE策略
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 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;
}

}

1
SourceGenerator.startNext

public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
…………………………..
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
//获取网络请求的对象loadData.HttpUrlFetcher
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;
}
// 这里创建了网络请求成功后的callback:DataCacheGenerator
private void cacheData(Object dataToCache) {
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
}

//网络请求fetcher.loadData
private void startNextLoad(final LoadData<?> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback() {
@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);
    }
  }
});

}

1
DecodeHelper.getLoadData > HttpGlideUrlLoader.buildLoadData

List<LoadData> getLoadData() { if (!isLoadDataSet) { isLoadDataSet = true; loadData.clear(); List> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
//noinspection ForLoopReplaceableByForEach to improve perf
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;
}
//buildLoadData这个函数就返回了HttpUrlFetcher,而HttpUrlFetcher是封装再LoadData对象里的.
public LoadData 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));
}

1
开始请求网络:HttpUrlFetcher.loadData > loadDataWithRedirects

@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
//返回InputStream
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
//把返回的InputStream返回给callback:DataCacheGenerator
callback.onDataReady(result);
}
}

//真正的网络请求再这里,返回InputStream
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.
}
}
//url:图片的网络地址
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);
} 

}

1
2
3

网络请求完成后,开始往回走了
DataCacheGenerator.onDataReady

public void onDataReady(Object data) {
cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
}

1
FetcherReadyCallback.onDataFetcherReady > DecodeJob.onDataFetcherReady >  decodeFromRetrievedData > decodeFromData > decodeFromFetcher >runLoadPath >  path.load LoadPth > LoadPth.loadWithExceptionList > path.decode DecodePath > DecodePath.decode

//开始解码了
public Resource decode(
DataRewinder rewinder,
int width,
int height,
@NonNull Options options,
DecodeCallback callback)
throws GlideException {
Resource decoded = decodeResource(rewinder, width, height, options);
Resource transformed = callback.onResourceDecoded(decoded);
return transcoder.transcode(transformed, options);
}

1
2
DecodePath.decodeResource > decodeResourceWithList > decoder.decode StreamBitmapDecoder.decode
这里就开始采用压缩,返回Bitmap

public Resource decode(
@NonNull InputStream source, int width, int height, @NonNull Options options)
throws IOException {

// Use to fix the mark limit to avoid allocating buffers that fit entire images.
final RecyclableBufferedInputStream bufferedStream;
final boolean ownsBufferedStream;
if (source instanceof RecyclableBufferedInputStream) {
  bufferedStream = (RecyclableBufferedInputStream) source;
  ownsBufferedStream = false;
} else {
  bufferedStream = new RecyclableBufferedInputStream(source, byteArrayPool);
  ownsBufferedStream = true;
}
ExceptionCatchingInputStream exceptionStream =
    ExceptionCatchingInputStream.obtain(bufferedStream);

MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream);
UntrustedCallbacks callbacks = new UntrustedCallbacks(bufferedStream, exceptionStream);
try {
  return downsampler.decode(invalidatingStream, width, height, options, callbacks);
} 

}

1
2
最终返回到DecodePath,因为我们是再DecodePath.decode的decodeResource里进来的:
再看下代码:

public Resource decode(
DataRewinder rewinder,
int width,
int height,
@NonNull Options options,
DecodeCallback callback)
throws GlideException {
Resource decoded = decodeResource(rewinder, width, height, options);
//这里把获取的图片返回到DecodeJob里:
Resource transformed = callback.onResourceDecoded(decoded);
//其实这里还会对图片进行处理优化
return transcoder.transcode(transformed, options);
}

public Resource onResourceDecoded(@NonNull Resource decoded) {
return DecodeJob.this.onResourceDecoded(dataSource, decoded);
}

1
2
3
DecodeJob.onResourceDecoded....> notifyEncodeAndRelease > notifyComplete
-> onResourceReady > EngineJob.onResourceReady > notifyCallbacksOfResult > entry.executor.execute(new CallResourceReady(entry.cb)) .... >EnginJob.loadFromActiveResources
最终把Bitmap存到了活动缓存里:

private EngineResource loadFromActiveResources(Key key) { EngineResource active = activeResources.get(key);
if (active != null) {
active.acquire();
}

return active;

}

1
接着再通过onResourceReady回调返回到SingleRequest里:这里有个target,这个target,就是我们再into开始时根据imageview创建的ImageViewTarget

private void onResourceReady(Resource resource, R result, DataSource dataSource) {
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
target.onResourceReady(result, animation);
}
}
notifyLoadSuccess();
}

1
ImageViewTarget,最终显示图片,DrawableImageViewTarget

public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}

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) {
view.setImageDrawable(resource);
}

1
2
3
4
## 生命周期分析

首先Activity中对生命周期的监听,也是参考这个方式:
还是从with的RequestManager开始:

private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
//空白的Fragment
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
//给到 RequestManager
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}

1
SupportRequestManagerFragment

@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
// ActivityFragmentLifecycle implements Lifecycle
// interface LifecycleListener 生命周期的监听接口
void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
所以当界面生命周期发生变化后,实现了LifecycleListener 接口的类,都会收到生命周期的回调监听.我们就可以针对具体的生命周期,执行对应逻辑处理.

```
// RequestManager
public synchronized 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);
}
// RequestTracker,pendingRequests缓存了等待执行的url请求
public void clearRequests() {
for (Request request : Util.getSnapshot(requests)) {
// It's unsafe to recycle the Request here because we don't know who might else have a
// reference to it.
clearAndRemove(request);
}
pendingRequests.clear();
}

缓存机制

缓存获取流程

先从活动缓存取,有,直接显示,没有从LRU内存缓存取,并LRU内存缓存的数据放入到活动缓存,并显示.如果LRU内存缓存没有,则从LRU磁盘缓存取,放入到活动缓存(磁盘缓存不移除)并显示,都没有,使用http请求下载或外部资源.下载完成缓存到磁盘缓存.
反向同理:生命周期onDestroy时,把活动缓存的移到LRU内存缓存.而下载的图片首先会存到磁盘缓存.
内存缓存大小:自动计算当前内存的1/8.
为什么要一个活动缓存?
如果图片再LRU内存缓存里,而正在显示的图片正在使用,而当有图片添加到LRU内存缓存后,有可能这个LRU内存缓存里的图片被清除了,这个时候就可能出问题了.

LRU Cache

其实就是一个LinkedHashMap,如果参数位true,就会执行LRU算法.数据put进,如果最终数据大于了maxSize,则就会把最少使用,最先添加的的数据清除,如果没有大于maxSize,添加的而是map中已经有的数据,则会把这条数据提到队尾,这再添加一个,就会把队首的数据删掉.

1
2
3
4
5
6
7
8
9
10
public class LruCache<K, V> {
private final LinkedHashMap<K, V> map;
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
}

参考资料

Glide中文文档