前言:上文《Glide源码顺藤摸瓜之with和load主线》,已经撸过了Glide的with和load主线,主要有生命周期方法的绑定、监听、分发和回调。这篇主要摸一摸into主线。
一、Glide的into主线关键类:
这条主线是Glide的重中之重:在这条主线里包括了Glide的核心功能:切换子线程去请求数据、它的缓存处理机制以及获取图片的stream后,切换为主线程转为为对应的格式交由ImageView显示。
- RequestManager:老生常谈,用来管理和start Glide请求的类。它根据绑定额生命周期的回调事件,自动的暂停、开始或者重启请求。
- RequestBuilder:
- DrawableImageViewTarget:继承至ImageViewTarget,它是最终请求成功返回后,将Drawable渲染到ImageView的Target
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
- BitmapImageViewTarget:同DrawableImageViewTarget只不过它是BitMap类型
@Override
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
- SingleRequest:它是一个图片资源请求
- TargetTracker:用来管理Target类似DrawableImageViewTarget和BitmapImageViewTarget,在生命周期回调中的加载动画的启停,因为它也监听了生命周期方法。由RequestManager回调它。
RequestManager.java
@Override
public synchronized void onStart() {
resumeRequests();
targetTracker.onStart();
}
TargetTracker.java
@Override
public void onStart() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onStart();
}
}
ImageViewTarget.java
@Override
public void onStart() {
if (animatable != null) {
animatable.start();
}
}
- RequestTracker:它用来管理Request队列,根据生命周期的回调取消、重启请求。
- Engine:负责启动加载和管理活动缓存和内存缓存的资源。
- ActiveResources:活动缓存
- LruResourceCache:继承至LruCache,利用trimMemory()函数实现对应用内存监控,根据内存消耗程度,适时释放资源。
- LruCache:内存缓存,利用Lru算法,最近使用算法。来管理内存缓存,它实际是使用LikedHashMap实现。
- EngineJob:其实它并不是一个Runnable或者线程啥的,它实现了DecodeJob.Callback回调方法,用来管理DecodeJob执行完请求后的回调,并回调给最外层。
- DecodeJob:首先它继承至Runnable,
二、Glide的into主线的源码跟踪:
- 点击进入into方法,它其实是进入了另一个into重载方法里。
这里还需要注意的是:
glideContext.buildImageViewTarget(view, transcodeClass)方法,它返回的DrawableImageViewTarget对象实例(如代码块中的2和3),它将负责请求图片资源数据回来后渲染设置到ImageView中。
另外需要注意的是Executors.mainThreadExecutor(),它是用来切换回主线程的,同OKHttp也是通过Handler(Looper.getMainLooper)切换回主线程。
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
...
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
2. GlideContext.java
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
3. ImageViewTargetFactory.java
public <Z> ViewTarget<ImageView, Z> buildTarget(...) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
...
}
}
4. Executor.java
private static final Executor MAIN_THREAD_EXECUTOR =
new Executor() {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(@NonNull Runnable command) {
handler.post(command);
}
};
- 进入到into重载方法中,我们需要聚焦的是:
buildRequest()方法:它最终返回的是一个SingleRequest对象
target.setRequest(request)方法: target根据上面实际是DrawableImageViewTarget对象,setRequest在它的父类ViewTarget,实际就是给View.setTag()设置Tag而已。
最重要的是requestManager.track(target, request),这又跑到RequestManager家里去了。下面继续跟踪
private <Y extends Target<TranscodeType>> Y into(...) {
Preconditions.checkNotNull(target);
Request request = buildRequest(target, targetListener, options, callbackExecutor);
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
- 跟踪requestManager.track(target, request)进入到RequestManager的track方法中。
targetTracker是用来管理Target在生命周期回调中的开启、暂停等(实际是加载动画的开启和暂停等)。
- 跟踪requestManager.track(target, request)进入到RequestManager的track方法中。
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
- 而requestTracker.runRequest()会将请求加入requests队列中,并开始执行request的begin()方法,在RequestTracker类中又两个队列,requests和pendingRequests。他们俩根据生命周期回调相互管理着request的启停。这里具体后面在细讲。
RequestTracker.java
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了。这里最重要的就是onSizeReady()方法了。
public void begin() {
...
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
}
...
}
}
- 在onSizeReady方法中,调用了engin.load()。467行需要注意一下,它传入this作为engin的回调方法,实际上就是SingleRequest自己。
SingleRequest.java
public void onSizeReady(int width, int height) {
...
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(),
467行 this, 这里得注意回调方法就是SingleRequst自己
callbackExecutor);
...
}
}
- 在Engine的load方法中,它将使用设置的图片信息生成一个Key,然后通过这个Key去活动缓存和内存缓存中去获取缓存,如果有就返回,没有的话就调用了waitForExistingOrStartNewJob()方法。
Engine.java
public <R> LoadStatus load(...) {
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,
...
startTime);
}
}
...
}
这里生成Key的话,进入到EventKey中,主要是对设置的属性进行hashCode值的拼接
EventKey.java
public int hashCode() {
if (hashCode == 0) {
hashCode = model.hashCode();
hashCode = 31 * hashCode + signature.hashCode();
hashCode = 31 * hashCode + width;
hashCode = 31 * hashCode + height;
hashCode = 31 * hashCode + transformations.hashCode();
hashCode = 31 * hashCode + resourceClass.hashCode();
hashCode = 31 * hashCode + transcodeClass.hashCode();
hashCode = 31 * hashCode + options.hashCode();
}
return hashCode;
}
- 从缓存中获取数据,如果获取到了就将缓存资源回调给SingleRequest。它将先从活动缓存中取,取不到再去内存缓存中获取。
这里活动缓存ActiveResources:内部使用一个Map缓存这资源弱引用,Map<Key, ResourceWeakReference> activeEngineResources;
而若是没有从活动缓存中获取数据,则会去内存缓存中获取,如果找到会直接从内存缓存中移除掉,并存入活动缓存中。cache.remove(key) > activeResources.activate(key, cached)
Engine.java
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
return active;
}
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
return cached;
}
return null;
}
private EngineResource<?> loadFromActiveResources(Key key) {
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
private EngineResource<?> loadFromCache(Key key) {
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
activeResources.activate(key, cached);
}
return cached;
}
- 若缓存中都没有的话,就会调用waitForExistingOrStartNewJob()方法。在这里面将会执行EnginJob.start(DecodeJob),也就是在线程池中执行DecodeJob,executor.execute(decodeJob)
private <R> LoadStatus waitForExistingOrStartNewJob(...) {
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
EngineJob<R> engineJob =
engineJobFactory.build(
key,
...
onlyRetrieveFromCache);
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
...
engineJob);
engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob);
}
- 在EngineJob中直接通过GlideExecutor来执行DecodeJob
EngineJob.java
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
三、Glide进入硬盘缓存和开始网络请求
3.1 前边跟踪到了EngineJob.start(),然后GlideExecutor.execute(decodeJob)执行了DecodeJob。而DecodeJob其实就是个Runnable,我们看看run()方法。
public void run() {
...
runWrapped();
...
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
}
}
3.2 进入到runWrapped()方法中,然后会进入到INITIALIZE项中,可以看到getNextGenerator()方法和runGenerators()方法。
getNextGenerator()方法其实是根据stage获得当前的Generator,然后通过runGenerators()执行generator.starNext()方法。
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);
}
}
private void runGenerators() {
...
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
...
}
}
3.3 其实这一步应该到了getNextGenerator()方法中,但是在这之前,我们应该提一下,再回顾一下Glide实例创建的时候做的事情,这对于下面分析getNextGenerator()方法很有帮助。
可以看到在实例化Glide对象的时候,它采用注册机的方式,将很多Decode解码器,Encode解码器,Transcoder转码器,Loader加载器,注册到了Register中,相当于把各种配方储存好,以便日后查找。每一条数据包括了输入的类型、输出类型和相匹配的各种Decode解码器,Encode解码器,Transcoder转码器,Loader加载器。
为后面在进行数据加载转换的时候找到相对应的工具,提供类似数据库的作用。
Glide(...) {
...
registry = new Registry();
registry.register(new DefaultImageHeaderParser());
...
registry.append(Bitmap.class, Bitmap.class, UnitModelLoader.Factory.<Bitmap>getInstance())
.append(GifDrawable.class, new GifDrawableEncoder())
/* GIF Frames */
// Compilation with Gradle requires the type to be specified for UnitModelLoader here.
.append(
GifDecoder.class, GifDecoder.class, UnitModelLoader.Factory.<GifDecoder>getInstance())
/* Files */
.register(new ByteBufferRewinder.Factory())
.append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory())
.append(File.class, InputStream.class, new FileLoader.StreamFactory())
.append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
.append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
.append(
String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
.append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(context.getAssets()))
.append(
Uri.class,
ParcelFileDescriptor.class,
new AssetUriLoader.FileDescriptorFactory(context.getAssets()))
.append(Uri.class, InputStream.class, new MediaStoreImageThumbLoader.Factory(context))
.append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())
.append(URL.class, InputStream.class, new UrlLoader.StreamFactory())
.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
.register(Bitmap.class, byte[].class, bitmapBytesTranscoder)
.register(
Drawable.class,
byte[].class,
new DrawableBytesTranscoder(
bitmapPool, bitmapBytesTranscoder, gifDrawableBytesTranscoder))
.register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);
...
}
3.4 在getNextGenerator()方法中,我们可以看到有三种Generator。
它前面两个其实是一个一个Genertaor寻找缓存,找到了就返回,没找到就到最后一个SourceGenerator开始进行网络请求 了。
- ResourceCacheGenerator:它是磁盘中获取,不过它是已经被处理过尺寸、宽高或者说裁剪采样转换过的磁盘缓存资源。
- DataCacheGenerator:它是从磁盘中获取数据,磁盘中使用的是Lru最近使用算法储存。它不同于ResourceCacheGenerator,它是未经处理的原始资源数据。
- SourceGenerator:如果前面两种磁盘缓存都没有数据的话,它将执行网络请求,然后将请求的资源数据缓存到磁盘中。
3.5 下面依次看到它们的startNext()方法
ResourceCacheGenerator.startNext()
ResourceCacheGenerator.java
@Override
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
...
1. currentKey =
new ResourceCacheKey( // NOPMD AvoidInstantiatingObjectsInLoops
// helper.getArrayPool(),
sourceId,
helper.getSignature(),
helper.getWidth(),
helper.getHeight(),
transformation,
resourceClass,
helper.getOptions());
2. cacheFile = helper.getDiskCache().get(currentKey);
if (cacheFile != null) {
sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
3. loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
4. loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
代码精简了下,大家可以自行跟踪下,看到代码中标出的1、2、3、4点,咱们来一一分析下:
- 第1点:通过各种参数如:sourceId(实际就是我们最开始传入的图片连接url、文件路径等等)、签名、宽高、转码方式等等。来生成一个ResourceCacheKey。
- 第2点:通过helper.getDiskCache().get()方法,通过key来查找是否有缓存的资源,这里的getDiskCache()实际返回的是DiskLruCacheWrapper对象。而它的DiskLruCacheWrapper.get()方法中getDiskCache()返回的就是DiskLruCache对象,它使用LinkHashMap结构来实现Lru算法。
DiskLruCacheWrapper.java
@Override
public File get(Key key) {
String safeKey = safeKeyGenerator.getSafeKey(key);
try {
final DiskLruCache.Value value = getDiskCache().get(safeKey);
if (value != null) {
result = value.getFile(0);
}
} catch (IOException e) {
}
return result;
}
private synchronized DiskLruCache getDiskCache() throws IOException {
if (diskLruCache == null) {
diskLruCache = DiskLruCache.open(directory, APP_VERSION, VALUE_COUNT, maxSize);
}
return diskLruCache;
}
-
第3点:首先modelLoader实际上就是我们上面讲到创建Glide实例时注册机方式里取出的加载器。如我们这里传入的时File类型,那么就会去找File.class类型的Loader加载器。
File.class类型的加载器
这里有四种,而这四种如果需要找到具体的加载器,那么还要根据第二个参数类型,也就是输入类型。这里分析下ByteBufferFileLoader.Factory,它的build()方法会返回一个ByteBufferFileLoader对象,其实这就是工厂模式啦~
通过调用ByteBufferFileLoader.buildLoadData()方法会返回一个LoadData实例。而这个LoadData实例有两个参数,第一个是Key,第二是一个DataFetcher的实现类。这里是ByteBufferFetcher。
public class ByteBufferFileLoader implements ModelLoader<File, ByteBuffer> {
@Override
public LoadData<ByteBuffer> buildLoadData(
@NonNull File file, int width, int height, @NonNull Options options) {
return new LoadData<>(new ObjectKey(file), new ByteBufferFetcher(file));
}
public static class Factory implements ModelLoaderFactory<File, ByteBuffer> {
public ModelLoader<File, ByteBuffer> build(@NonNull MultiModelLoaderFactory multiFactory) {
return new ByteBufferFileLoader();
}
}
}
- 第4点: loadData.fetcher.loadData(),它实际就是调用通过第3点中返回的LoadData里的Fetcher对象的loadData()方法。这里接着第3点的分析的话,就是ByteBufferFetcher.loadData()方法。它就是将缓存文件转成ByteBuffer类型然后回调给前台。
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
callback.onLoadFailed(e);
return;
}
callback.onDataReady(result);
}
3.5 如果ResourceCacheGenerator没有找到缓存数据的话,就会接着去DataCacheGenerator里的startNext()方法找缓存数据。
DataCacheGenerator.java
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
1. Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
2. cacheFile = helper.getDiskCache().get(originalKey);
if (cacheFile != null) {
this.sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
3. loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
4. loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
这里的1、2、3、4点其实和上面的ResourceCacheGenerator里的一致,只不过它的cacheKey不一样,Key originalKey = new DataCacheKey(sourceId, helper.getSignature());它是一个DataCacheKey,我们也可以看到这里生成Key,就不想ResourceCacheGenerator有很多参数了。这里就两个参数,sourceId是指我们调用Glide加载图片时传入的uri或者文件路径啥的,还有签名。这也可以验证这里就是去寻找原始未经处理的缓存资源。
3.7 如果前面两个Generator都没有在磁盘找到缓存资源,那么就会去最后一个终极大Boss-->SourceGenerator.startNext()方法中处理了。
SourceGenerator.java
@Override
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
1. cacheData(data);
}
startNextLoad(loadData);
}
return started;
}
private void startNextLoad(final LoadData<?> toStart) {
2. loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {... });
}
- 有缓存的话就直接取缓存数据了
- 没有缓存的话,那么就依旧原来模式loadData.fetcher.loadData()。只不过这里的fetcher是HttpUrlFetcher,这里的loadData由HttpGlideUrlLoader生成。我们看看路径:
1. Glide.java
547行 .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
2. HttpGliderUrlLoader.java
public LoadData<InputStream> buildLoadData(...) {
return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {
return new HttpGlideUrlLoader(modelCache);
}
}
3.8 基于前面,进入到HttpUrlFetcher.java中看看loadData方法
HttpUrlFetcher.java
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
...
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
...
}
进入到loadDataWithRedirects()方法中:
private InputStream loadDataWithRedirects(...) throws IOException {
...
urlConnection = connectionFactory.build(url);
...
urlConnection.connect();
1. stream = urlConnection.getInputStream();
final int statusCode = urlConnection.getResponseCode();
if (isHttpOk(statusCode)) {
2. return getStreamForSuccessfulRequest(urlConnection);
} else if (isHttpRedirect(statusCode)) {
String redirectUrlString = urlConnection.getHeaderField("Location");
URL redirectUrl = new URL(url, redirectUrlString);
3. return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else if (statusCode == INVALID_STATUS_CODE) {
throw new HttpException(statusCode);
} else {
throw new HttpException(urlConnection.getResponseMessage(), statusCode);
}
}
- 它是使用HttpURLConnection来请求资源数据的。
- 如果请求成功了调用getStreamForSuccessfulRequest()方法,验证数据完整性,就是对于一下数据的length: ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength)
- 如果有重定向的话,则获取header中的location自动的重定向url,并重新请求。
四、获取数据后回调显示
上面我们已经跟踪到了最后通过网络请求获取资源了,接下来按照开发逻辑就是回调数据,通知上层切换线程,并展示图片了。
下面我们来分析分析(三个Generator都是一致的):
- HttpUrlFetcher.loadData(57行 callback.onDataReady) -->
- SourceGenerator.onDataReadyInternal(148行 cb.onDataFetcherReady)(这里将网络获取数据存入磁盘缓存起来) --->
- DecodeJob.onDataFetcherReady --->
- DecodeJob.decodeFromRetrievedData() --->
- DecodeJob.notifyEncodeAndRelease() --->
- DecodeJob.notifyComplete(337行 callback.onResourceReady()) --->
- EngineJob.onResourceReady() --->
- EngineJob.notifyCallbacksOfResult()(261行 entry.executor.execute(new CallResourceReady(entry.cb))) --->
- EngineJob.CallResourceReady.run() ---->
- EngineJob.callCallbackOnResourceReady()(158行 cb.onResourceReady(engineResource, dataSource)) ---->
- SingleRequest.onResourceReady(631行 target.onResourceReady(result, animation) target就是我们之前说得ImageViewTarget) ---->
- ImageViewTarget.onResourceReady() --->
- ImageViewTarget.setResourceInternal() --->
- DrawableImageViewTarget.setResource()(它是ImageViewTarget的子类)
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
}
回调过程就没有详细写了,跟了个路径。到最后获取的图片资源通过一层层的回调,最终到了target中,在target的setResource方法中,交由原始的view去渲染,最终图片得以显示出来。
五、遗留的问题
基于这两篇文章,我们把Glide的三条主线摸清楚了,Glide的工程确实很庞大,看的有些累,我们基于主线,一条条的跑通,那么它的主要架构其实在心里已经有谱了,现在只剩下些边角需要我们受试一波:
- 1、Glide如何切换为子线程请求数据?
- 2、Glide通过网络请求获取数据后怎么缓存磁盘的?
- 3、Glide获取图片数据后如何切换为主线程渲染?
- 4、Glide的三级缓存如何交互以及如何监控内存?
- 5、Glide如何监控网络实现重启图片加载?
- 6、Glide如何根据Activity生命周期开始和暂停请求?
这一篇文章篇幅够长了,所以剩下的问题,咱们下一篇Glide继续来。
网友评论