和以前的文章会有必定的不一样,这主要是由于Glide
自身的源码量致使的问题,由于我是最后写的前言,你会发如今文章刚开始时会代码复制的比较彻底,后面就比较零散,并且一部分我直接用本身话去进行了表述。若是真的要看懂,建议仍是对着Glide
的源码进行查看,这样会帮助你更好去理解GLide
的它的实现流程。java
(1)资源引入android
repositories {
mavenCentral()
google()
}
dependencies {
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}
复制代码
(2)方法使用git
// 实现单张图片加载
@Override public void onCreate(Bundle savedInstanceState) {
ImageView imageView = (ImageView) findViewById(R.id.my_image_view);
// 若是是最新版的系统是不容许http来进行请求的
// 去百度随便拿一张图片的地址来改一下就行了
Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}
// 实现图片列表加载
@Override public View getView(int position, View recycled, ViewGroup container) {
final ImageView myImageView;
if (recycled == null) {
myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false);
} else {
myImageView = (ImageView) recycled;
}
String url = myUrls.get(position);
Glide
.with(myFragment)
.load(url)
.centerCrop()
.placeholder(R.drawable.loading_spinner)
.into(myImageView);
return myImageView;
}
复制代码
在源码使用中,其实基础的在上面的使用方法中已经讲述到了,一共能够分为三个步骤:github
咱们的分析流程也将围绕这三个函数来进行展开。算法
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getContext()).get(fragment);
}
@SuppressWarnings("deprecation")
@Deprecated
@NonNull
public static RequestManager with(@NonNull android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
@NonNull
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
复制代码
悄咪咪数了数,Oh my Gosh!!! 居然高达有6个重载方法。不过呢想必你也发现这些方法都直接调用了getRetriever().get()
的方法,那目的就很是明显了,咱们进到这个方法去一探究竟了。缓存
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
return Glide.get(context).getRequestManagerRetriever(); // 1 -->
}
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
// 使用了context.getApplicationContext()是为了防止内存泄漏的发生
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
// 对glide总体地进行初始化
// 其中就包含了对RequestManagerRetriever的初始化流程
// 代码量比较大就不作介绍了
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
复制代码
既然是一堆的初始化操做,最后咱们的目标又是RequestManagerRetriever
这个类,那天然是有必要对这个类进行探究的。网络
public class RequestManagerRetriever implements Handler.Callback {
public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
this.factory = factory != null ? factory : DEFAULT_FACTORY;
handler = new Handler(Looper.getMainLooper(), this /* Callback */);
}
private static final RequestManagerFactory DEFAULT_FACTORY =
new RequestManagerFactory() {
@NonNull
@Override
public RequestManager build( @NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
}
};
// getRetriever()的get()方法
// 对标上面的6个重载方法的调用,这里只取其一
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
// 若是当前的线程是在后台线程中,则进入
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext()); // 1-->
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); // 2 -->
}
}
}
复制代码
(1)经过构造函数咱们可以猜想的内容是通讯的工具是Handler
,而Looper
使用的是MainLooper
也就是主线程的,那说明最后异步通讯也就直接扔到主线程完成了。app
(2)经过get()
函数,能够发现其实分为两个部分。一是再一层的get()
方法;二是supportFragmentGet()
或者是FragmentGet()
方法。异步
他们最后的任务都是为了建立出一个RequestManager
,可是咱们得关注一下它的建立方式。maven
get()
对于这个方法而言就是对context
的断定是否为Application
,而后给出相应的结果。
(1)不是Application
且是在主线程中时
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
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
复制代码
而他们的归宿,最后仍是回到咱们上方的重载方法。
(2)是Application
或是再也不主线程时
getApplicationManager(context); // 1 -->
// 使用DCL的方式来建立了单例
@NonNull
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) {
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(), // 2
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
复制代码
经过工厂来自建了一个RequestManager
,注释2处他直接使用了ApplicationLifecycle
缘由是由于某些状况下会接受不到生命周期的事件,这里是作的强制性的操做是为了生命周期变化时可以正常相应。
FragmentGet()
瞟了一下,这是要一个废弃的方法了,可是和supportFragmentGet()
的方法相比其实也差不太多。
private RequestManager fragmentGet( @NonNull Context context, @NonNull android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible); // 1 -->
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);
// 将requestManager和Fragment相挂钩
// 用以完成生命周期的监听
current.setRequestManager(requestManager);
}
return requestManager;
}
// 1 -->
// 获取对应的Fragment
private RequestManagerFragment getRequestManagerFragment( @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) {
// 寻找的方式是经过设置的TAG
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
// 先去等待队列中进行查询
// 这一步的做用是防止Fragment的重复添加
// 由于添加的Fragment的所谓的生命周期有必定的延时性
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
// 若是等待队列建立一个新的TAG
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
复制代码
总结
Glide
的同时在内部完成了RequestManagerRetriever
的建立RequestManagerRetriever
调用get()
方法,获取到RequestManager
,获取方式分为如下两种:
Context
为Application
时, 经过getApplicationManager()
方法建立RequestManager
完成,将生命周期的监听与Application
强制绑定用于接收。Context
不为Application
时, 经过supportFragmentGet()
方法建立RequestManager
完成,生命周期的监听是与Fragment
进行绑定实现。建立对应TAG的一个很是直接的好处,咱们的图片像RecyclerView
会放置中不容易出现错位的现象。
整体来讲上面的就是一个初始化和必要变量获取的操做,那接下从函数方法来看咱们彷佛是要去得到的图片了呢。
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string); // 1 -->
}
复制代码
注释1处,咱们经过观察能够知道他最后会选择将获取的数据转化变成一个Drawable
的类而后再在咱们对应的ImageView
上来进行显示。那咱们就对asDrawable()
先进行一段源码的分析。
// asDrawable()不断深刻能发现调用到的函数
// 是完成一个类RequestBuilder的对象建立
public <ResourceType> RequestBuilder<ResourceType> as( @NonNull Class<ResourceType> resourceClass) { // Drawable.class
return new RequestBuilder<>(glide, this, resourceClass, context);
}
复制代码
那接下来的问题就要进入到这个类中,由于在前面咱们的探索其实算是并无什么收获的,而若是只是建立一个类显然是不会让这句话显得这么重要,那关键点必定会出如今这个类的构造中了。
protected RequestBuilder( @NonNull 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()); // 1 -->
// 这段代码过长,不作展现,它的主要任务就是一些策略开关
// 各类选项的开启装置,好比错误提示、优先级、磁盘缓存策略、固定宽高等等
apply(requestManager.getDefaultRequestOptions());
}
// 1-->
// 从某种意义上讲就是对生命周期的监听
private void initRequestListeners(List<RequestListener<Object>> requestListeners) {
for (RequestListener<Object> listener : requestListeners) {
addListener((RequestListener<TranscodeType>) listener);
}
}
复制代码
而若是回到load(string)
方法。
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
复制代码
他最后的差事也就是将URI
的值放到了model
这个变量中,那整个load()
函数做用其实最后只是建立了一个RequestBuilder
的事例,那最后的获取和加载工做确定是在into()
函数中才进行了操做的。
into(ImageView)
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// 经过scaleType,对图片的属性进行设定
switch (view.getScaleType()) {
case CENTER_CROP:
// 。。。。。。
default:
// Do nothing.
}
}
// 正式将图片数据塞入
// 1 -->
return into(
// 2 -->
glideContext.buildImageViewTarget(view, transcodeClass), // 深度调用能够知道也就是将View进行了赋值
/*targetListener=*/ null,
requestOptions,
// 可以看到线程池的影子,后面的图片的获取和处理咱们猜想就是经过池来进行处理
Executors.mainThreadExecutor());
}
// 1 --> 将数据塞入
private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) {
// 正常状况构建SingleRequest的请求
// 由于thumbnail通常须要额外的需求
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); // 3 -->
return target;
}
复制代码
下面的内容将主要对上述代码中的注释2和注释3进行讲解。
glideContext.buildImageViewTarget(view, transcodeClass)
从字面意思,相比你也可以进行理解了,就是要构建一个存放的目标。
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget( @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass); // 1 -->
}
// 1-->
// 根据不一样的数据类型选择存储是以Drawable仍是Bitmap构建
public <Z> ViewTarget<ImageView, Z> buildTarget( @NonNull ImageView view, @NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
// 以Bitmap构建
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view); // 2-->
} else if (Drawable.class.isAssignableFrom(clazz)) {
// 以Drawable构建
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view); // 2 -->
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
// 2-->
// 两个注释最后深度调用以后都会调用到这段代码
// 若是单看这段代码的时候其实
public ViewTarget(@NonNull T view) {
this.view = Preconditions.checkNotNull(view);
// 若是只看这个构造函数,确实没什么东西
// 不行你能够直接看注释3的代码处
sizeDeterminer = new SizeDeterminer(view); // 3 -->
}
// 很是简单的就只是对view进行了一个赋值操做
SizeDeterminer(@NonNull View view) {
this.view = view;
}
复制代码
DrawableImageViewTarget
和
BitmapImageViewTarget
的其余方法,能发现这样的一个特征。
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
复制代码
没错!! 赋值操做,这个操做说明最后其实的结束点确定是在这里的,而调用他的函数最后也就是onResourceReady()
这个方法,也就意味着图片获取成功了,不过呢这个请求完成确定是和数据的获取相互关联的,也就是下面部分的内容了。
requestManager.track(target, request)
// 以同步的方式完成数据的请求
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target); // 对当前的目标的生命周期有一个追踪
requestTracker.runRequest(request); // 2 --> 执行操做正式开启
}
// 2 -->
public void runRequest(@NonNull Request request) {
requests.add(request);
// 会对当前的全部请求作一个判断处理
// 会根据当前的状态肯定是否要进行数据加载的操做
// 通常来讲对应的就是生命周期
if (!isPaused) {
request.begin();
} else {
request.clear();
pendingRequests.add(request);
}
}
复制代码
那上面一段代码说明咱们正常运行的时候,网络传输的操做确定是已经在正常运行了的,而其实正常没有设置时调用的会是SingleRequest
的类,很少逼逼,瞅瞅它的begin()
方法有什么特殊之处了。
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;
}
// ==============重中之重==============
// 由于在上述文章中讲到过了图片的大小问题
// 在Glide中这里就是给出解决方案的地方,两种方案:
// 1. 给出了固定长宽
// 2. 没有设置时
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());
}
}
}
复制代码
那接下来要讲述的内容就应该是他的一些大小设置问题了,Glide
究竟是用什么样的方式完成大小的设置的呢?
onSizeReady(overrideWidth, overrideHeight)
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
// .....
status = Status.RUNNING;
// 对长宽从新进行预估
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
loadStatus =
engine.load(各类参数);
// .....
}
}
复制代码
经过观察对onSizeReady()
函数发现,他使用的方案其实又是一个名叫作engine.load()
的方式。
public <R> LoadStatus load(各类参数) {
EngineResource<?> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(各类参数);
}
}
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
复制代码
上述是我省略事后的代码,他表达意思其实很是之简单:
(1)内存里有数据,你就从我内存里拿。
(2)内存里没数据,那你就本身建立一个。
这样想来,问题又要往下继续延伸了,正常来讲咱们没有数据啊,那就要去调用这个waitForExistingOrStartNewJob()
方法,来完成图片数据的获取了。
private <R> LoadStatus waitForExistingOrStartNewJob(各类参数) {
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
return new LoadStatus(cb, current);
}
EngineJob<R> engineJob =
engineJobFactory.build(各类参数);
DecodeJob<R> decodeJob =
decodeJobFactory.build(各类参数);
jobs.put(key, engineJob); // 对当前驱动工做进行缓存操做
engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob); // 开启图片获取工做
return new LoadStatus(cb, engineJob);
}
复制代码
可以注意到有出现两个新的类EngineJob
和DecodeJob
,转换成中文去理解就是工做驱动器和解码工做,而且EngineJob
内部与线程池搭噶,最后确定用于完成最后的图片获取工做,而DecodeJob
做为被运行的工做,处理逻辑就应该在其之中。
public void run() {
DataFetcher<?> localFetcher = currentFetcher;
try {
// .....
runWrapped(); // 1 -->
} catch (Exception e) {
// .....
} finally {
// .....
}
}
// 1 -->
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
// 获取 Stage.INITIALIZE 的下一步操做,也就是选择三种方案
// 1. 资源缓存:ResourceCacheGenerator
// 2. 数据缓存:DataCacheGenerator
// 3. 网络资源:SourceGenerator
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);
}
}
复制代码
其实上述内容中已经开始讲述到咱们常见的三大缓存了,也就是网络缓存、磁盘缓存和内存缓存,这段代码中其实已经开始涉及网络缓存和磁盘缓存了。
SourceGenerator:关于网络缓存
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) { // 1 -->
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
// 只对Source这个枚举类型相应
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// 已完成就通知失败
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
// 1-->
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()) {
// 从映射表找出可以对应上的图片类型的ModelLoader
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;
}
复制代码
针对注释1进行探讨,这里的话,咱们就尽可能不放代码查看了,由于看了这么多代码,你确定也累了。其实你可以猜想到它的下一步是网络请求,那若是获取成功了,是要直接进行图片数据的显示吗?那三次缓存应该在什么时机进行操做呢?由于代码量的缘由,这里咱们用图来展现流程。
从图中能够知道,其实从网络获取的资源最后仍是要被放到磁盘中进行缓存的,而磁盘缓存成功以后,接下来要干的事情就是要去通知View
把获取的数据进行解码。这里你是否有必定的疑问了?
你没有听错,就是解码,若是你去各个官方查看图片的时候,不少给的都是后期从新被编码过的数据,自己数据其实并不可以在直接运行的,而解码就是让图片正式可视化的必经之路,也就是DecodeJob
的本质工做了,对应的函数就是decodeFromRetrievedData()
方法,把磁盘中拷贝出来的数据要进行解码操做。
private void decodeFromRetrievedData() {
Resource<R> resource = null;
// 将网络获取的数据进行解码操做
try {
resource = decodeFromData(currentFetcher, currentData, currentDataSource); // 1 -->
} catch (GlideException e) {
}
// 解码完成,发出通知
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource); // 2-->
} else {
runGenerators();
}
}
复制代码
你可以发现我在这段代码中打了两个注释,其实对应的就是两大操做解码完成,通知能够显示了。
decodeFromData(currentFetcher, currentData, currentDataSource);
下面会给出一段很长的深度调用代码。
(1)resource = decodeFromData(currentFetcher, currentData, currentDataSource);
(2)Resource<R> result = decodeFromFetcher(data, dataSource);
(3)return path.load(
rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
(4)return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
(5)result = path.decode(rewinder, width, height, options, decodeCallback);
(6)
public Resource<Transcode> decode( DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
// 这里会有不少转化的方法,通常来讲对图片最多见的就是转成Bitmap
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
return transcoder.transcode(transformed, options);
}
复制代码
在decode()
这个函数其实作了三件事:
decodeResource
将原始数据转换成咱们原始图片的过程;callback.onResourceDecoded()
是当获得了原始图片以后对图片继续处理过程;transcoder.transcode()
会使用BitmapDrawableTranscoder
进行再包装decodeResource中能够转化的部分解码器
那这个时候你就正式拿到了一张图片了,那下一步还须要干吗???显示啊!!!废了这么大周折,还不赶忙拿去显示,不是作了一大堆无用功嘛?
notifyEncodeAndRelease(resource, currentDataSource);
只看少许代码来完成这项工做
(1)notifyComplete(result, dataSource);
(2)
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource);
}
复制代码
你是否有注意到这样的问题,onResourceReady()
是否是有点眼熟,在很上面的glideContext.buildImageViewTarget(view, transcodeClass)
,也就是构建放置的目标中咱们就已经讲到过这个方法了,最后会经过一个set()
的方法来将数据进行放置。
那基本上来讲,上面就是一个比较详细的Glide
的源码分析,由于代码是在太多了,因此我这里删去了不少。
其实你会发现我并无正式讲完三级缓存,还差一个内存缓存没讲不是?
其实这是一个很早就被用到的方法,他对应的位置就在SingleRequest
被调用了OnSizeReady()
方法的时候有个engine.load()
,里面就包含了第三级缓存内存缓存,里面对应的是这样的一段代码memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
以及他深度调用后的EngineResource<?> active = loadFromActiveResources(key);
从活跃的的资源数据中进行寻找。一样是一个很是简单的实现手法。
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
复制代码
就是经过一个Map
对数据进行了保存,这样从复用的角度上来看就被比较好的继承了。
但若是不是活跃资源数据呢?
不要着急,还有一些数据还会在cache
的变量中被保存着,这个方法里就是用了咱们常常会说起到的LRUCache
的一个淘汰算法,这里的详细请查看个人另一篇文章:Glide都在用的LruCache,你学会了吗?。