glide现在已经4.x了, 就以该版本的源码进行分析了.
glide优势
Glide.with(this)
initializeGlide()
解码资源的接口(如将File, InputStream etc 解码为Bitmap, Drawable etc): public interface ResourceDecoder
将数据编码写入持久性数据存储区(如本地文件缓存)的接口: public interface Encoder
将一种类型的资源转码为另一种类型的资源(如Resources转BitmapDrawable): public interface ResourceTranscoder
将任意复杂的数据模型转换为具体的数据类型的工厂接口(如请求网络获取原始流): public interface ModelLoader
RequestManager.load(url)
/**
* 指定ResourceType为Drawable, transcodeClass为Drawable.class
*/
public RequestBuilder as(
@NonNull Class resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
/**
* 结合上面方法:load(url)后 model类型为String, transcodeClass为Drawable.class
*/
public RequestBuilder load(@Nullable String string) {
return asDrawable().load(string);
}
生命周期绑定
传入的不同类型的参数Fragment、Activity、Context、Application创建一个没有界面的 RequestManagerFragment , 返回 RequestManager 对象, 为了绑定生命周期将 RequestManagerFragment 的属性 ActivityFragmentLifecycle 传递到 RequestManager, 让 RequestManager 将自己注册到 ActivityFragmentLifecycle 的观察者集合, 从而在 RequestManagerFragment 的生命周期方法中通知事件订阅者. 构造 RequestManager 对象时初始化了 RequestManager.glide 属性 , 此时 glide的属性, 注册不同格式数据源的编码、解码器对象, 不同数据来源的加载器对象, 图片对象变换器, 编码转换器等被初始化.
资源加载器、转换器、编码器、变换器、内存缓存、硬盘缓存、active缓存对象的初始化
// glide对象的属性
private Engine engine;
private BitmapPool bitmapPool;
private MemoryCache memoryCache; // LruResourceCache 原数据内存缓存
private ExecutorService sourceService; // FIFO 网络请求线程池
private ExecutorService diskCacheService; // FIFO 磁盘操作线程池
private DecodeFormat decodeFormat;
private DiskCache.Factory diskCacheFactory; // 磁盘操作接口类DiskCache
// 为 Engine 类的属性, 构造glide对象时初始化glide.engine属性
private final Map jobs;
private final EngineKeyFactory keyFactory;
private final MemoryCache cache;
private final EngineJobFactory engineJobFactory;
private final Map>> activeResources;
private final ResourceRecycler resourceRecycler;
private final LazyDiskCacheProvider diskCacheProvider;
RequestManager.load(url)
根据as(Drawable.class)参数类型Drawable.class构建RequestBuilder(Glide glide, RequestManager requestManager, Class
RequestBuilder.into(imageView)
转换为
RequestBuilder.into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions);
其中glideContext是在Glide的构造方法中初始化的, 使用工厂模式根据参数的classType从ImageViewTargetFactory构造一个(ViewTarget
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
void track(@NonNull Target> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
执行网络请求的地方
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);
}
}
真正的加载是在Engine.load()中的DecodeJob.run();
public LoadStatus load(...) {
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);
return null;
}
// 内存缓存
EngineResource> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
return null;
}
EngineJob> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
return new LoadStatus(cb, current);
}
EngineJob engineJob = engineJobFactory.build(...);
DecodeJob decodeJob = decodeJobFactory.build(..., engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);
}
runWrapped()
private void runWrapped() {
switch (runReason) { // 初始化为INITIALIZE
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE); // 递归获取值为 Stage.SOURCE
currentGenerator = getNextGenerator(); // 返回 new SourceGenerator(decodeHelper, this);
runGenerators(); /** 执行SourceGenerator.startNext()下载网络图片 */
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
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);
}
}
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);
}
}
加载数据的入口
使用OkHttp加载数据并回调
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher> fetcher,
DataSource dataSource, Key attemptedKey) {
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
解码和转码
private void decodeFromRetrievedData() {
Resource 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();
}
}
从注册的解码器集合中查找能处理原数据的解码器
解码
解码变换完成切换线程
String类型的url默认是HttpUrlFetcher.loadData()加载图片, 回调是SourceGenerator.onDataReady()
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);
}
}
从网络加载图片数据OkHttpStreamFetcher
硬盘缓存加载时序图
测试的时候硬盘缓存策略使用的是DiskCacheStrategy.DATA
public static final DiskCacheStrategy DATA = new DiskCacheStrategy() {
@Override
public boolean isDataCacheable(DataSource dataSource) {
return dataSource != DataSource.DATA_DISK_CACHE && dataSource != DataSource.MEMORY_CACHE;
}
@Override
public boolean isResourceCacheable(boolean isFromAlternateCacheKey, DataSource dataSource,
EncodeStrategy encodeStrategy) {
return false;
}
@Override
public boolean decodeCachedResource() {
return false;
}
@Override
public boolean decodeCachedData() {
return true;
}
};
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);
}
}
解转码流程
缓存相关类
硬盘缓存相关类: DiskLruCacheFactory、 DiskLruCacheWrapper、InternalCacheDiskCacheFactory
硬盘缓存读取 DiskLruCacheWrapper.get() 的调用方:
DataCacheGenerator.startNext() 尝试先从磁盘缓存中读取, 未获取到再从网络读取;
ResourceCacheGenerator.startNext() 尝试先从磁盘缓存中读取, 未获取到再从网络读取.
硬盘缓存存储 DiskLruCacheWrapper.put() 的调用方:
DecodeJo$DeferredEncodeManager.encode()存储到硬盘
内存缓存相关类: LruResourceCache、ActiveResources
ActiveResources.activate()的调用方:
Engine.load() -> Engine.loadFromCache() ;
Engine.onEngineJobComplete().
ActiveResources.get()的调用方:
Engine.load() -> Engine.loadFromActiveResources()
ActiveResources.deactivate()的调用方:
Engine.onResourceReleased()
LruResourceCache.remove()的调用方:
Engine.load() -> Engine.loadFromCache() -> Engine.getEngineResourceFromCache()
LruResourceCache.put()的调用方:
Engine.onResourceReleased();
Engine.cache.setResourceRemovedListener(Engine.this);
BitmapPool相关类: LruBitmapPool
变化工具类: TransformationUtils
SimpleTarget的使用追踪
DownsampleStrategy内置了几个DownsampleStrategy.CenterOutside
// sourceWidth 服务器端返回的图片宽度
// requestedWidth UI控件的宽度
// 返回缩放百分比的较大值
public float getScaleFactor(int sourceWidth, int sourceHeight, int requestedWidth,
int requestedHeight) {
float widthPercentage = requestedWidth / (float) sourceWidth;
float heightPercentage = requestedHeight / (float) sourceHeight;
return Math.max(widthPercentage, heightPercentage);
}
关键问题代码
int targetWidth = requestedWidth == Target.SIZE_ORIGINAL ? sourceWidth : requestedWidth;
int targetHeight = requestedHeight == Target.SIZE_ORIGINAL ? sourceHeight : requestedHeight;
具体的缩放因子与ImageView控件的scaleType有关, 参考类DownsampleStrategy
options.inTargetDensity > 0 && options.inDensity
Glide.with(MainActivity.this)
.load(url)
.into(imageView);
分析一下调用后此处图片的宽高和控件的宽高:
RequestBuilder.into()中通过工厂类ImageViewTargetFactory.buildTarget()获取DrawableImageViewTarget对象;
执行SingleRequest.begin()的
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
调用的是ViewTarget.getSize(), 其实是调用的ViewTarget$SizeDeterminer.getSize(),核心是
if (layoutListener == null) {
ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
observer.addOnPreDrawListener(layoutListener);
}
private static final class SizeDeterminerLayoutListener
implements ViewTreeObserver.OnPreDrawListener {
private final WeakReference sizeDeterminerRef;
SizeDeterminerLayoutListener(@NonNull SizeDeterminer sizeDeterminer) {
sizeDeterminerRef = new WeakReference<>(sizeDeterminer);
}
@Override
public boolean onPreDraw() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "OnGlobalLayoutListener called attachStateListener=" + this);
}
SizeDeterminer sizeDeterminer = sizeDeterminerRef.get();
if (sizeDeterminer != null) {
sizeDeterminer.checkCurrentDimens();
}
return true;
}
}
再回到SingleRequest.onSizeReady()继续执行. 到执行InputStream解码的时候, 会根据控件的scaleType、宽高和返回的图片流数据中的宽高做缩放, 使用了Option.inSample属性.
下次分析:
每次图片加载都new 一个Engine?
参考文档
官网介绍: http://bumptech.github.io/glide/doc/transformations.html
详细blog: https://blog.csdn.net/yanfeivip8/article/details/50418064
郭霖blog: https://blog.csdn.net/guolin_blog/article/details/53759439