目录
- 1.使用Gilde显示一张图片
- 2.Glide with操作源码解析
- 3.Glide 的load操作
- 4.Glide的into流程解析
- 5.Glide
1.使用Gilde显示一张图片
Glide.with(this). | |
load("https://cn.bing.com/sa/simg/hpb/xxx.jpg") | |
.into(imageView); |
上边是Glide最简单的来显示一张图片,虽然只有三步操作:with、load、into,但是gilde却通过大量的代码在维护着。
with:返回一个RequestManager
load:返回一个RequestBuilder
下面通过源码分析这三块,重点是Glide生明周期的管理和缓存的使用,以及整个加载的流程的梳理。
2.Glide with操作源码解析
Glide的with函数由于参数类型原因有多个重载,下面选择传入Activity当做参数的
public static RequestManager with(@NonNull Activity activity) { | |
return getRetriever(activity).get(activity); | |
} |
这个方法就是得到一个RequestManager
分析getRetriever
private static RequestManagerRetriever getRetriever(@Nullable Context context) { | |
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(); | |
} |
得到一个RequestManagerRetriever,这个管理RequestManager
RequestManagerRetriever的get方法
public RequestManager get( 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 | |
// Only unwrap a ContextWrapper if the baseContext has a non-null application context. | |
// Context#createPackageContext may return a Context without an Application instance, | |
// in which case a ContextWrapper may be used to attach one. | |
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) { | |
return get(((ContextWrapper) context).getBaseContext()); | |
} | |
} | |
return getApplicationManager(context); | |
} |
根据不同的参数类型,执行不同的代码逻辑。
参数是:FragmentActivity的源码
public RequestManager get( FragmentActivity activity) { | |
if (Util.isOnBackgroundThread()) { | |
return get(activity.getApplicationContext()); | |
} else { | |
assertNotDestroyed(activity); | |
frameWaiter.registerSelf(activity); | |
FragmentManager fm = activity.getSupportFragmentManager(); | |
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); | |
} | |
} |
注意这里判断了线程,如果是子线程会直接走ApplicationContext类型的函数重载。
supportFragmentGet方法:
private RequestManager supportFragmentGet( | |
Context context, | |
FragmentManager fm, | |
Fragment parentHint, | |
boolean isParentVisible) { | |
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint); | |
RequestManager requestManager = current.getRequestManager(); | |
if (requestManager == null) { | |
// TODO(b/): Factor out this Glide.get() call. | |
Glide glide = Glide.get(context); | |
requestManager = | |
factory.build( | |
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); | |
// This is a bit of hack, we're going to start the RequestManager, but not the | |
// corresponding Lifecycle. It's safe to start the RequestManager, but starting the | |
// Lifecycle might trigger memory leaks. See b/ | |
if (isParentVisible) { | |
requestManager.onStart(); | |
} | |
current.setRequestManager(requestManager); | |
} | |
return requestManager; | |
} |
这个方法会创建一个空白的SupportRequestManagerFragment,这个Fragment的作用很重要,也是Glide的核心,声明周期的管理就是靠这个来监控的。
监控了:onStart、onStop、onDestroy,所以Glide在使用的时候,我们不用关心资源的释放,因为Glide会自动释放资源,释放资源的依据就是这个声明周期的管理。
get函数参数是:ApplicationContext 的源码
private RequestManager getApplicationManager( { Context context) | |
// Either an application context or we're on a background thread. | |
if (applicationManager == null) { | |
synchronized (this) { | |
if (applicationManager == null) { | |
Glide glide = Glide.get(context.getApplicationContext()); | |
applicationManager = | |
factory.build( | |
glide, | |
new ApplicationLifecycle(), | |
new EmptyRequestManagerTreeNode(), | |
context.getApplicationContext()); | |
} | |
} | |
} | |
return applicationManager; | |
} |
可见当参数类型是:ApplicationContext或者子线程调用with方法不会创建空白的Fragmnet来进行生命周期的监控,也不会进行资源释放,所以在调用with方法的时候不能传ApplicationContext。
下面分析Glide分别在onStart、onStop、onDestroy执行了那些逻辑
RequestManager的onStart方法
public synchronized void onStart() { | |
resumeRequests(); | |
targetTracker.onStart(); | |
} |
执行了刷新请求和Tracker的onStart,resumeRequests这个跟请求的缓存的使用
RequestTracker 的resumeRequests方法
public void resumeRequests() { | |
isPaused = false; | |
for (Request request : Util.getSnapshot(requests)) { | |
if (!request.isComplete() && !request.isRunning()) { | |
request.begin(); | |
} | |
} | |
pendingRequests.clear(); | |
} |
将运行队列requests所有没有完成又处于停止状态的任务全部开始执行,requests是一个正在运行的请求缓存集合,这是一个set集合,处于等待状态的请求队列pendingRequests进行清理操作。这个就是Glide感应到声明周期onStart进行的操作。
RequestManager的onStop方法
public synchronized void onStop() { | |
pauseRequests(); | |
targetTracker.onStop(); | |
} |
RequestTracker的pauseRequests方法
public void pauseRequests() { | |
isPaused = true; | |
for (Request request : Util.getSnapshot(requests)) { | |
if (request.isRunning()) { | |
request.pause(); | |
pendingRequests.add(request); | |
} | |
} | |
} |
request.pause():将所有的运行缓存集合中的请求进行暂停操作,并将这些请求加入到等待缓存请求集合pendingRequests
RequestManager的onDestroy
public synchronized void onDestroy() { | |
targetTracker.onDestroy(); | |
for (Target<?> target : targetTracker.getAll()) { | |
clear(target); | |
} | |
targetTracker.clear(); | |
requestTracker.clearRequests(); | |
lifecycle.removeListener(this); | |
lifecycle.removeListener(connectivityMonitor); | |
Util.removeCallbacksOnUiThread(addSelfToLifecycle); | |
glide.unregisterRequestManager(this); | |
} |
可以看到Glide在感应到onDestroy会进行各种资源释放,监听的移除操作。
3.Glide 的load操作
RequestManager的load方法
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) { | |
return asDrawable().load(bitmap); | |
} | |
public RequestBuilder<Drawable> asDrawable() { | |
return as(Drawable.class); | |
} | |
public <ResourceType> RequestBuilder<ResourceType> as( | |
@NonNull Class<ResourceType> resourceClass) { | |
return new RequestBuilder<>(glide, this, resourceClass, context); | |
} |
load方法返回值是RequestBuilder,通过new的方式进行创建
RequestBuilder的构造方法
protected RequestBuilder( | |
Glide glide, | |
RequestManager requestManager, | |
Class<TranscodeType> transcodeClass, | |
Context context) { | |
this.glide = glide; | |
this.requestManager = requestManager; | |
this.transcodeClass = transcodeClass; | |
this.context = context; | |
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass); | |
this.glideContext = glide.getGlideContext(); | |
initRequestListeners(requestManager.getDefaultRequestListeners()); | |
apply(requestManager.getDefaultRequestOptions()); | |
} |
initRequestListeners:初始化监听
apply:校验参数
load的过程比较简单,重点的into将会非常复杂
4.Glide的into流程解析
public <Y extends Target<TranscodeType>> Y into() { Y target | |
return into(target, /*targetListener=*/ null, Executors.mainThreadExecutor()); | |
} | |
<Y extends Target<TranscodeType>> Y into( | |
Y target, | |
RequestListener<TranscodeType> targetListener, | |
Executor callbackExecutor) { | |
return into(target, targetListener, /*options=*/ this, callbackExecutor); | |
} |
into另外一个重载方法:
private <Y extends Target<TranscodeType>> Y into( | |
Y target, | |
RequestListener<TranscodeType> targetListener, | |
BaseRequestOptions<?> options, | |
Executor callbackExecutor) { | |
Preconditions.checkNotNull(target); | |
if (!isModelSet) { | |
throw new IllegalArgumentException("You must call #load() before calling #into()"); | |
} | |
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; | |
} |
buildRequest 会通过SingleRequest.obtain,创建一个SingleRequest,这个必须要前置了解,后边的流程需要用到。
requestManager.track(target, request):这个是主流程,下面来看RequestManager的track方法
RequestManager的track方法
synchronized void track(@NonNull Target<?> target, @NonNull Request request) { | |
targetTracker.track(target); | |
requestTracker.runRequest(request); | |
} |
RequestTracker的runRequest方法
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); | |
} | |
} |
这里的Request是一个接口,调用了begin方法,这个Request就是前面创建的SingleRequest
SingleRequest的begin
public void begin() { | |
synchronized (requestLock) { | |
... | |
if (status == Status.COMPLETE) { | |
onResourceReady( | |
resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false); | |
return; | |
} | |
cookie = GlideTrace.beginSectionAsync(TAG); | |
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)); | |
} | |
} | |
} |
如果没有设置宽高会调用 target.getSize(this)来获取大小,如果设置了会执行onSizeReady方法
SingleRequest的onSizeReady方法
public void onSizeReady(int width, int height) { | |
stateVerifier.throwIfRecycled(); | |
synchronized (requestLock) { | |
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, | |
callbackExecutor); | |
if (status != Status.RUNNING) { | |
loadStatus = null; | |
} | |
if (IS_VERBOSE_LOGGABLE) { | |
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime)); | |
} | |
} | |
} |
接下来调用Engin的load方法
Engin的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, | |
Executor callbackExecutor) { | |
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() :; | |
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); | |
} | |
} | |
// Avoid calling back while holding the engine lock, doing so makes it easier for callers to | |
// deadlock. | |
cb.onResourceReady( | |
memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false); | |
return null; | |
} |
loadFromMemory这个方法是先从缓存中去查找,如果有直接就可以直接使用了
loadFromMemory方法
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; | |
} |
loadFromActiveResources:从活动缓存查找,如果有直接返回使用,这个缓存是一个Map集合
loadFromCache:从内存缓存查找,如果有直接使用,这个是一个LRU集合
上边两个是都是内存缓存,只要显示在页面上的,都会缓存在活动缓存。
Engin的waitForExistingOrStartNewJob方法
private <R> LoadStatus waitForExistingOrStartNewJob( | |
GlideContext glideContext, | |
Object model, | |
Key signature, | |
int width, | |
int height, | |
Class<?> resourceClass, | |
Class<R> transcodeClass, | |
Priority priority, | |
DiskCacheStrategy diskCacheStrategy, | |
Map<Class<?>, Transformation<?>> transformations, | |
boolean isTransformationRequired, | |
boolean isScaleOnlyOrNoTransform, | |
Options options, | |
boolean isMemoryCacheable, | |
boolean useUnlimitedSourceExecutorPool, | |
boolean useAnimationPool, | |
boolean onlyRetrieveFromCache, | |
ResourceCallback cb, | |
Executor callbackExecutor, | |
EngineKey key, | |
long startTime) { | |
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); | |
if (current != null) { | |
current.addCallback(cb, callbackExecutor); | |
if (VERBOSE_IS_LOGGABLE) { | |
logWithTimeAndKey("Added to existing load", startTime, key); | |
} | |
return new LoadStatus(cb, current); | |
} | |
EngineJob<R> engineJob = //这个是线程池的管理者这个里边存着各个管理 | |
engineJobFactory.build( | |
key, | |
isMemoryCacheable, | |
useUnlimitedSourceExecutorPool, | |
useAnimationPool, | |
onlyRetrieveFromCache); | |
DecodeJob<R> decodeJob = //这个是具体的任务 | |
decodeJobFactory.build( | |
glideContext, | |
model, | |
key, | |
signature, | |
width, | |
height, | |
resourceClass, | |
transcodeClass, | |
priority, | |
diskCacheStrategy, | |
transformations, | |
isTransformationRequired, | |
isScaleOnlyOrNoTransform, | |
onlyRetrieveFromCache, | |
options, | |
engineJob); | |
jobs.put(key, engineJob); | |
engineJob.addCallback(cb, callbackExecutor); | |
engineJob.start(decodeJob); | |
if (VERBOSE_IS_LOGGABLE) { | |
logWithTimeAndKey("Started new load", startTime, key); | |
} | |
return new LoadStatus(cb, engineJob); | |
} |
engineJob 管理一个线程池,decodeJob这个是任务的抽象是一个Runable,所以下面就会执行任务的run方法
DecodeJob的run方法
public void run() { | |
... | |
try { | |
if (isCancelled) { | |
notifyFailed(); | |
return; | |
} | |
runWrapped(); | |
} catch (CallbackException e) { | |
// If a callback not controlled by Glide throws an exception, we should avoid the Glide | |
// specific debug logic below. | |
throw e; | |
} catch (Throwable t) { | |
.. | |
} finally { | |
// Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call | |
// close in all cases anyway. | |
if (localFetcher != null) { | |
localFetcher.cleanup(); | |
} | |
GlideTrace.endSection(); | |
} | |
} |
DecodeJob的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); | |
} | |
} |
默认会执行case INITIALIZE的runGenerators(),getNextGenerator得到的是SourceGenerator,这个必须要明确,否则走不下去。
SourceGenerator的startNext方法
public boolean startNext() { | |
... | |
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; | |
startNextLoad(loadData); | |
} | |
} | |
return started; | |
} |
DecodeHelper的getLoadData方法
List<LoadData<?>> getLoadData() { | |
if (!isLoadDataSet) { | |
isLoadDataSet = true; | |
loadData.clear(); | |
List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model); | |
//noinspection ForLoopReplaceableByForEach to improve perf | |
for (int i =, 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; | |
} |
HttpGlideUrlLoader的buildLoadData方法
public LoadData<InputStream> buildLoadData( | |
int width, int height, Options options) { | GlideUrl model,|
// 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); | |
if (url == null) { | |
modelCache.put(model,, 0, model); | |
url = model; | |
} | |
} | |
int timeout = options.get(TIMEOUT); | |
return new LoadData<>(url, new HttpUrlFetcher(url, timeout)); | |
} |
可以看到最终返回的是包含HttpUrlFetcher的loadData
SourceGenerator的startNextLoad方法
private void startNextLoad(final LoadData<?> toStart) { | |
loadData.fetcher.loadData( | |
helper.getPriority(), | |
new DataCallback<Object>() { | |
@Override | |
public void onDataReady(@Nullable Object data) { | |
if (isCurrentRequest(toStart)) { | |
onDataReadyInternal(toStart, data); | |
} | |
} | |
@Override | |
public void onLoadFailed(@NonNull Exception e) { | |
if (isCurrentRequest(toStart)) { | |
onLoadFailedInternal(toStart, e); | |
} | |
} | |
}); | |
} |
loadData.fetcher的fetcher就是HttpUrlFetcher
HttpUrlFetcher的loadData方法
public void loadData( | |
super InputStream> callback) { | Priority priority, DataCallback<?|
long startTime = LogTime.getLogTime(); | |
try { | |
InputStream result = loadDataWithRedirects(glideUrl.toURL(),, 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)); | |
} | |
} | |
} |
loadDataWithRedirects方法
private InputStream loadDataWithRedirects( | |
URL url, int redirects, URL lastUrl, Map<String, String> headers) throws HttpException { | |
if (redirects >= MAXIMUM_REDIRECTS) { | |
throw new HttpException( | |
"Too many (> " + MAXIMUM_REDIRECTS + ") redirects!", INVALID_STATUS_CODE); | |
} else { | |
// Comparing the URLs using .equals performs additional network I/O and is generally broken. | |
// See http://michaelscharf.blogspot.com//11/javaneturlequals-and-hashcode-make.html. | |
try { | |
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) { | |
throw new HttpException("In re-direct loop", INVALID_STATUS_CODE); | |
} | |
} catch (URISyntaxException e) { | |
// Do nothing, this is best effort. | |
} | |
} | |
urlConnection = buildAndConfigureConnection(url, headers); | |
try { | |
// 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 #. | |
stream = urlConnection.getInputStream(); | |
} catch (IOException e) { | |
throw new HttpException( | |
"Failed to connect or obtain data", getHttpStatusCodeOrInvalid(urlConnection), e); | |
} | |
... | |
} |
到这里就看到urlConnection拿到图片的InputStream,终于从一个网络链接请求到流了,然后就是将流转成bitmap显示的过程了,感兴趣的可以继续查看。
5.Glide
声明周期和缓存总结 Glide 调用with函数如果传入的ApplicationContext或者在子线程不会为我们创建空白的Fragment,不会进行生命周期的监控,也就不会进行资源自动释放,所以不用传ApplicationContext。其他情况glide会自动创建空白的Fragment来进行生命周期监控,并自动进行资源释放。
Glide的缓存分为4级缓存:活动缓存、内存缓存、磁盘缓存、网络缓存
- 活动缓存,是一个Map集合,加载图片会首先从这个缓存里边查找。
- 内存缓存,是一个LRU缓存集合,如果获取缓存没有就从内存缓存查找。
- 磁盘缓存,是disklrucache缓存集合,如果从内存缓存没有找到就从磁盘缓存查找。
- 网络缓存,如果磁盘缓存没有就需要从网络上就行请求加载了。