Glide:提供了一些列静态方法(with)用来获取RequestManager,并维护了Engine、BitmapPool、DiskCache、MemoryCache这几个类。Glide实现了ComponentCallbacks2接口,当内存不足时,会调用trimMemory方法,
在这个方法里,调用ArrayPool、BitmapPool、MemoryCache的trimMemory(level),减少缓存大小。
MemoryCache:将资源添加到内存或者从内存移除资源,实现类是LruResourceCache。
BitmapPool:Bitmap重用池,HONEYCOMB以上版本,实现类是LruBitmapPool,以下版本实现类是BitmapPoolAdapter。
ArrayPool:数组池的接口,用于存储不同类型的数组,实现类是LruArrayPool,一个固定大小的数组,数组使用LRU淘汰池策略保持池的最大字节大小下。
Engine:负责启动下载和管理活动、缓存资源。Engine类维护了EngineJob的集合,EngineKeyFactory、EngineJobFactory、DecodeJobFactory。
EngineJob:通过添加和移除回调的方式来管理下载。
EngineKeyFactory:生成EngineKey。
EngineJobFactory:Engine的静态内部类。用来创建EngineJob。
DecodeJob:解码从缓存或网络获取的资源。
DecodeHelper:解码帮助类,用来获取对应的ModelLoader,获取LoadData。
LoadData:包含了一组Key对应的确定的资源,如果缓存里没有资源,会通过DataFetcher获取。
DecodeJobFactory:Engine的静态内部类。用来生成DecodeJob。
HttpUrlFetcher:通过url从网络下载图片。
ModelLoader:工厂接口,用来将任意复杂的数据模型转化为具体的数据类型,可以使用一个DataFetcher获取数据资源为代表的模型。
Registry:管理组件注册。
HttpGlideUrlLoader:ModelLoader的实现类,将URL转化成Data(InputStream)。
Request:为Target下载资源。实现类为SingleRequest。
Target:Glide可以加载资源到Target实现类持有的ImageView等实例。继承了LifecycleListener,在加载的过程中,可以通知相关生命周期。
BaseTarget:加载资源的一个抽象基类,实现了基本方法 或 空实现。持有Request实例。
DiskCacheStrategy:硬盘缓存策略。
DataFetcherGenerator:用来注册到ModelLoaders。
DataCacheGenerator:实现DataFetcherGenerator接口,startNext方法中ModelLoader为ByteBufferFileLoader,DataFetcher为ByteBufferFetcher。
当调用Glide.with()方法时,在RequestManagerRetriever.supportFragmentGet中调用Glide.get(Context context)方法,可以获取Glide单例。
public static Glide get(Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
//先检查AndroidManifest.xml中是否有自己的配置,实现GlideModule接口,
//如果有调用applyOptions的,设置自己的配置
Context applicationContext = context.getApplicationContext();
List modules = new ManifestParser(applicationContext).parse();
GlideBuilder builder = new GlideBuilder(applicationContext);
for (GlideModule module : modules) {
module.applyOptions(applicationContext, builder);
}
//通过GlideBuilder创建Glide,在createGlide方法中,初始化线程池、各种缓存的类、Engine,
//并用这些参数,新建Glide实例。
glide = builder.createGlide();
for (GlideModule module : modules) {
module.registerComponents(applicationContext, glide.registry);
}
}
}
}
在Glide构造方法中,根据数据Class类型将编解码的类注册到registry中。
registry.register(ByteBuffer.class, new ByteBufferEncoder())
.register(InputStream.class, new StreamEncoder(arrayPool))
......
初始化GlideContext。
glideContext = new GlideContext(context, registry, imageViewTargetFactory,
defaultRequestOptions, engine, this, logLevel);
RequestManager.load方法的作用主要是根据ResourceType(这里是Drawable.class)新建RequestBuilder,并将url设置给RequestBuilder.model。
随后调用into(ImageView view)方法,设置需要展示图片的ImageView,并根据ResourceType,创建对应类型的Traget,这里是DrawableImageViewTarget。
构建好Target之后,调用into(Target target)方法,开启一个请求。
public > Y into(@NonNull Y target) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//从target获取request,如果不为null,先清除当前的request,
//做的主要操作就是从RequestTracker.requests里移除request,
//并调用Request的recycle方法,将request的数据(回调、等)置为null。
//移除成功以后,将Target从TargetTracker.targets里移除,并将Target的request置为null。
Request previous = target.getRequest();
if (previous != null) {
requestManager.clear(target);
}
requestOptions.lock();
//为Target构建一个Request实例(实现类为SingleRequest).
Request request = buildRequest(target);
target.setRequest(request);//给target设置tag。
//将target添加到TargetTracker.targets集合里,
//将request添加到RequestTracker.requests集合里,并调用SingleRequest的begin方法,开始一个请求
requestManager.track(target, request);
return target;
}
在SingleRequest的begin方法中,如果overrideWidth和overrideHeight不是有效值,先通过target.getSize(this)获取图片的尺寸。
ViewTarget#getSize
void getSize(SizeReadyCallback cb) {
int currentWidth = getViewWidthOrParam();
int currentHeight = getViewHeightOrParam();
if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) {
int paddingAdjustedWidth = currentWidth == WindowManager.LayoutParams.WRAP_CONTENT
? currentWidth
: currentWidth - ViewCompat.getPaddingStart(view) - ViewCompat.getPaddingEnd(view);
int paddingAdjustedHeight = currentHeight == LayoutParams.WRAP_CONTENT
? currentHeight
: currentHeight - view.getPaddingTop() - view.getPaddingBottom();
//获取到view尺寸后,回调SingleRequest的onSizeReady方法,这个方法中,调用Engine.load方法, 开启一个下载任务。
cb.onSizeReady(paddingAdjustedWidth, paddingAdjustedHeight);
} else {
// We want to notify callbacks in the order they were added and we only expect one or two
// callbacks to
// be added a time, so a List is a reasonable choice.
if (!cbs.contains(cb)) {
cbs.add(cb);
}
if (layoutListener == null) {
final ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
observer.addOnPreDrawListener(layoutListener);
}
}
}
在这里也get了一个获取view尺寸的新方法,
private int getSizeForParam(int param, boolean isHeight) {
if (param == LayoutParams.WRAP_CONTENT) {
Point displayDimens = getDisplayDimens();
return isHeight ? displayDimens.y : displayDimens.x;
} else {
return param;
}
}
private Point getDisplayDimens() {
if (displayDimens != null) {
return displayDimens;
}
WindowManager windowManager =
(WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
displayDimens = new Point();
display.getSize(displayDimens);
} else {
displayDimens = new Point(display.getWidth(), display.getHeight());
}
return displayDimens;
}
Engine.load方法
根据URL路径、图片尺寸等参数生成key以后,首先从内存缓存和弱引用里查找资源,如果不存在,进入下载流程。
......
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
......
EngineResource> cached = loadFromCache(key, isMemoryCacheable);
......
EngineResource> active = loadFromActiveResources(key, isMemoryCacheable);
......
//生成EngineJob 和 DecodeJob
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable,
useUnlimitedSourceExecutorPool);
DecodeJob decodeJob = decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
onlyRetrieveFromCache,
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb);//cb是SingleRequest
engineJob.start(decodeJob);
EngineJob#public void start(DecodeJob decodeJob) {
//首先根据是否从缓存中解码,来选择对应的线程池,开启任务,执行decodeJob的run方法。
//decodeJob.willDecodeFromCache()返回true,请见下面方法解析。
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
Log.i(TAG,"executor.class = "+decodeJob.willDecodeFromCache());
executor.execute(decodeJob);
}
DecodeJob.run()中runWrapped方法,会根据RunReason的改变,生成不同的操作类,比如从缓存查找,从网络下载等,进行不同的操作,
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//此时的stage = RESOURCE_CACHE。currentGenerator 为 ResourceCacheGenerator
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);
}
}
/**
* 1.第一次调用,返回的stage为RESOURCE_CACHE, currentGenerator是ResourceCacheGenerator,调用startNext方法,返回false
* 2.继续调用getNextStage(stage)方法,此时,返回的stage为DATA_CACHE,currentGenerator为DataCacheGenerator,调用startNext方法从硬盘缓存查找,如果没有缓存,返回false。
* 3.继续调用getNextStage(stage)方法,返回stage为Stage.SOURCE。currentGenerator为SourceGenerator,调用reschedule()方法,
* 将runReason 置为 RunReason.SWITCH_TO_SOURCE_SERVICE;调用EngineJob.reschedule方法,在这个方法中,又会通过线程池,调用DecodeJob的run方法。
* 5.此时的currentGenerator 为 SourceGenerator,在startNext方法中,通过HttpUrlFetcher.loadData方法从网络获取图片,回调SourceGenerator的onDataReady方法,
* 将Inputstream流数据赋值给SourceGenerator.dataToCache,并调用DecodeJob.reschedule方法,EngineJob.reschedule,又回到DecodeJob的getNextStage方法,此时返回stage为FINISHED
*再次调用SourceGenerator的startNext方法,将数据缓存到硬盘,调用DataCacheGenerator.startNext方法,调用onDataReady,这个方法里又调用SourceGenerator的onDataFetcherReady
* 然后到DecodeJob.onDataFetcherReady,将runReason 置为 RunReason.DECODE_DATA;终于来到decodeFromRetrievedData()这个方法了。
* 6.decodeFromRetrievedData()将数据解析成BitmapDrawable,在notifyEncodeAndRelease方法中调用notifyComplete,调用EngineJob的onResourceReady方法,在这个方法里
* 经过Engine.onEngineJobComplete--cb(SingleRequest).onResourceReady(engineResource, dataSource)--onResourceReady----target.onResourceReady(result, animation)
* 给view设置资源。
*
*/
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.
}