上一篇文章分析了Glide中with与load方法的加载流程,如果没有看上一篇的请查看(点击打开链接),接下来继续分析into的加载流程。
一、into方法
public Target<TranscodeType> into(ImageView view) { //检查是否在主线程,如果不在抛出异常 Util.assertMainThread(); //检查View是否为空,为空抛出异常 Preconditions.checkNotNull(view); if (!requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed() && view.getScaleType() != null) { if (requestOptions.isLocked()) { requestOptions = requestOptions.clone(); } //判断View设置的requestOptions的类型,设置View的居中、裁剪、平铺等参数 switch (view.getScaleType()) { case CENTER_CROP: requestOptions.optionalCenterCrop(); break; case CENTER_INSIDE: requestOptions.optionalCenterInside(); break; case FIT_CENTER: case FIT_START: case FIT_END: requestOptions.optionalFitCenter(); break; case FIT_XY: requestOptions.optionalCenterInside(); break; case CENTER: case MATRIX: default: // Do nothing. } } //核心方法:1、buildImageViewTarget 2、into return into(glideContext.buildImageViewTarget(view, transcodeClass), requestOptions); }
1、buildImageViewTarget
public <X> ViewTarget<ImageView, X> buildImageViewTarget( @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) { return imageViewTargetFactory.buildTarget(imageView, transcodeClass); } //一个工厂方法,负责生产正确的数据类型,返回正确的实例对象 public class ImageViewTargetFactory { @NonNull @SuppressWarnings("unchecked") public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view, @NonNull Class<Z> clazz) { if (Bitmap.class.equals(clazz)) { //返回Bitmap类型ViewTarget return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view); } else if (Drawable.class.isAssignableFrom(clazz)) { //返回Drawable类型ViewTarget return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view); } else { throw new IllegalArgumentException( "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); } } }
不管是BitmapImageViewTarget还是DrawableImageViewTarget都继承自ImageViewTarget只是泛型中传递的参数不一样。他们的继承关系如下:
DrawableImageViewTarget/BitmapImageViewTarget ——> ImageViewTarget<Z> ——> ViewTarget<ImageView, Z> ——>BaseTarget<Z> ——> Target<R>(inteface) ——> LifecycleListener(inteface)
(1)LifecycleListener:是一个持有组件(比如 activity 或者 fragment等)生命周期状态信息的接口,用于监听Activity或者fragment的生命周期。
public interface LifecycleListener { //开始加载组件 void onStart(); //停止加载组件 void onStop(); //销毁加载组件 void onDestroy(); }
(2)Target<R>(inteface):继承自LifecycleListener,观察泛型种参数View变化时候的声明周期。
public interface Target<R> extends LifecycleListener { //给定初始宽高 int SIZE_ORIGINAL = Integer.MIN_VALUE; //开始加载图片 void onLoadStarted(@Nullable Drawable placeholder); //加载失败 void onLoadFailed(@Nullable Drawable errorDrawable); //加载图片完成 void onResourceReady(@NonNull R resource, @Nullable Transition<? super R> transition); //图片加载取消 void onLoadCleared(@Nullable Drawable placeholder); //初始化尺寸 void getSize(@NonNull SizeReadyCallback cb); //移除回调 void removeCallback(@NonNull SizeReadyCallback cb); //设置Request void setRequest(@Nullable Request request); //获取Request Request getRequest(); }
(3)BaseTarget<Z>:实现Target接口,他是一个抽象类,重写了Target中所有的抽象方法。
public abstract class BaseTarget<Z> implements Target<Z> { private Request request; //设置request对象 @Override public void setRequest(@Nullable Request request) { this.request = request; } //获取request对象 @Override public Request getRequest() { return request; } //取消加载 @Override public void onLoadCleared(@Nullable Drawable placeholder) { // Do nothing. } //开始加载图片 @Override public void onLoadStarted(@Nullable Drawable placeholder) { // Do nothing. } //加载图片失败 @Override public void onLoadFailed(@Nullable Drawable errorDrawable) { // Do nothing. } //开始加载动画 @Override public void onStart() { // Do nothing. } //加载动画停止 @Override public void onStop() { // Do nothing. } //图片销毁 @Override public void onDestroy() { // Do nothing. } }
(4)ViewTarget<ImageView, Z>:继承自BaseTarget,分为两大部分,第一部分用于View添加和移除的操作以及tag设置,这里面涉及到一个Request接口,主要用来加载请求资源时候的回调;另一个是内部类SizeDeterminer,它主要用于获取设置调整图片尺寸相关。
public abstract class ViewTarget<T extends View, Z> extends BaseTarget<Z> { ………………………………………………………………………省略部分代码…………………………………………………………………………………… public final ViewTarget<T, Z> clearOnDetach() { if (attachStateListener != null) { return this; } attachStateListener = new OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { //当View被添加到Window时候回调 resumeMyRequest(); } @Override public void onViewDetachedFromWindow(View v) { //当View被被Window移除时候回调 pauseMyRequest(); } }; maybeAddAttachStateListener(); return this; } @SuppressWarnings("WeakerAccess") @Synthetic void resumeMyRequest() { //获取在setRequest方法里面设置的tag Request request = getRequest(); if (request != null && request.isPaused()) { //获取request接口,设置加载View开始的回调 request.begin(); } } @SuppressWarnings("WeakerAccess") @Synthetic void pauseMyRequest() { //获取在setRequest方法里面设置的tag Request request = getRequest(); if (request != null && !request.isCancelled() && !request.isPaused()) { isClearedByUs = true; //获取request接口,设置加载View结束的回调 request.pause(); isClearedByUs = false; } } ………………………………………………………………………省略部分代码…………………………………………………………………………………… static final class SizeDeterminer { ………………………………………………………………………省略尺寸计算代码…………………………………………………………………………………… }
(5)ImageViewTarget<Z>:继承自ViewTarget,并且实现Transition.ViewAdapter接口:
public interface Transition<R> { interface ViewAdapter { //获取View View getView(); //获取Drawable Drawable getCurrentDrawable(); //设置Drawable void setDrawable(Drawable drawable); } //是否设置动画 boolean transition(R current, ViewAdapter adapter); }
ImageViewTarget里面主要是处理View动画开启与敢关闭监听图片加载过程做出相应操作,如加载开始、加载中、加载错误、加载空布局等图片。BitmapImageViewTarget与此类似。
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>implements Transition.ViewAdapter { private Animatable animatable; //初始化View的尺寸 public ImageViewTarget(ImageView view) { super(view); } //初始化View的尺寸 public ImageViewTarget(ImageView view, boolean waitForLayout) { super(view, waitForLayout); } //获取当前View的Drawable对象 @Override public Drawable getCurrentDrawable() { return view.getDrawable(); } //设置当前View的Drawable对象 @Override public void setDrawable(Drawable drawable) { view.setImageDrawable(drawable); } //设置加载占位图 @Override public void onLoadStarted(@Nullable Drawable placeholder) { super.onLoadStarted(placeholder); setResourceInternal(null); setDrawable(placeholder); } //设置加载失败 @Override public void onLoadFailed(@Nullable Drawable errorDrawable) { super.onLoadFailed(errorDrawable); setResourceInternal(null); setDrawable(errorDrawable); } //取消加载 @Override public void onLoadCleared(@Nullable Drawable placeholder) { super.onLoadCleared(placeholder); if (animatable != null) { animatable.stop(); } setResourceInternal(null); setDrawable(placeholder); } //加载完成 @Override public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) { if (transition == null || !transition.transition(resource, this)) { setResourceInternal(resource); } else { maybeUpdateAnimatable(resource); } } //开始动画 @Override public void onStart() { if (animatable != null) { animatable.start(); } } //结束动画 @Override public void onStop() { if (animatable != null) { animatable.stop(); } } //子类实现设置外部图片资源 private void setResourceInternal(@Nullable Z resource) {. setResource(resource); maybeUpdateAnimatable(resource); } private void maybeUpdateAnimatable(@Nullable Z resource) { if (resource instanceof Animatable) { animatable = (Animatable) resource; animatable.start(); } else { animatable = null; } } //子类实现设置图片资源 protected abstract void setResource(@Nullable Z resource); }
(6)DrawableImageViewTarget
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> { public DrawableImageViewTarget(ImageView view) { //View初始化 super(view); } @Override protected void setResource(@Nullable Drawable resource) { //设置图片 view.setImageDrawable(resource); } }
现在总结上部分,buildImageViewTarget返回的是ViewTarget:
(1)由RequestBuilder构造方法传递过来的class对象通过ImageViewTargetFactory创建对应XxxImageViewTarget。
(2)XxxImageViewTarget继承自ImageViewTarget,最终实现了View生命周期的监听,从而对View的加载的整个过程进行监听。
2、into
作用:创建新的请求,根据tag获取旧的请求并且进行比较,如果一致回收掉新建的请求,使用旧的request请求;否则清除旧的tag,添加新的请求并且开始请求。
private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, @NonNull RequestOptions options) { //是否为主线程 Util.assertMainThread(); //检查tag是否为nul Preconditions.checkNotNull(target); //检查设置的URL是否为空 if (!isModelSet) { throw new IllegalArgumentException("You must call #load() before calling #into()"); } //获取配置参数 options = options.autoClone(); //创建新的请求对象,Request为一个接口,用于监控请求,请求过程请看(二、Request的创建过程)说明 Request request = buildRequest(target, targetListener, options); //根据target获取到Request Request previous = target.getRequest(); //如果和新建的请求和获取的请求一致,并且没有缓存,请求已经完成,则回收新建的请求recycle() if (request.isEquivalentTo(previous) && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { request.recycle(); //如果旧的请求没有在运行,则开启之前请求 if (!Preconditions.checkNotNull(previous).isRunning()) { previous.begin(); } return target; } //清除tag的值 requestManager.clear(target); //给tag设置新的request target.setRequest(request); //添加tag,开始请求 requestManager.track(target, request); return target; }
二、Request的创建过程分析
buildRequest没有处理其他事情,直接返回的是buildRequestRecursive方法,因此直接看buildRequestRecursive方法:
private Request buildRequestRecursive( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, //请求监听相关接口 @Nullable RequestCoordinator parentCoordinator, //请求协调相关接口 TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, //RequestOptions设置的优先级 int overrideWidth, //RequestOptions设置的宽度 int overrideHeight, //RequestOptions设置的高度 RequestOptions requestOptions) { ………………………………………………………………………省略部分代码…………………………………………………………………………………… Request mainRequest = buildThumbnailRequestRecursive( target, targetListener, parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight, requestOptions); ………………………………………………………………………省略部分代码…………………………………………………………………………………… }
接下来看看方法buildThumbnailRequestRecursive:
private Request buildRequestRecursive( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, //请求监听相关接口 @Nullable RequestCoordinator parentCoordinator, //请求协调相关接口 TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, //RequestOptions设置的优先级 int overrideWidth, //RequestOptions设置的宽度 int overrideHeight, //RequestOptions设置的高度 RequestOptions requestOptions) { ………………………………………………………………………省略部分代码…………………………………………………………………………………… Request mainRequest = buildThumbnailRequestRecursive( target, targetListener, parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight, requestOptions); ………………………………………………………………………省略部分代码…………………………………………………………………………………… } 接下来看看方法buildThumbnailRequestRecursive: private Request buildThumbnailRequestRecursive( Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, @Nullable RequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight, RequestOptions requestOptions){ //与略缩图相关设置判断逻辑判断,直接进入obtainRequest ………………………………………………………………………省略部分代码…………………………………………………………………………………… return obtainRequest( target, targetListener, requestOptions, parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight); } }
obtainRequest调用的是SingleRequest类中obtain方法,他是一个单独的加载资源类,实现了Request接口:
public static <R> SingleRequest<R> obtain( Context context, GlideContext glideContext, Object model, Class<R> transcodeClass, RequestOptions requestOptions, int overrideWidth, int overrideHeight, Priority priority, Target<R> target, RequestListener<R> targetListener, RequestListener<R> requestListener, RequestCoordinator requestCoordinator, Engine engine, TransitionFactory<? super R> animationFactory) { SingleRequest<R> request = (SingleRequest<R>) POOL.acquire(); if (request == null) { request = new SingleRequest<>(); } //这里调用init方法进行构造方法赋值,这样Request的实现类就获得了初始值 request.init( context, glideContext, model, transcodeClass, requestOptions, overrideWidth, overrideHeight, priority, target, targetListener, requestListener, requestCoordinator, engine, animationFactory); return request; }
以上就是Request的创建过程过程,这个过程完成了Request的初始,但是整个请求过程还没开始。
三、请求加载的过程分析
1、begin方法开始加载
在1.2 into方法中有previous.begin(); requestManager.track(target, request);两行代码,track最终调用的还是Request的begin方法,表示开启一个异步的请求,在Request的实现类SingleRequest方法中找到该方法。
@Override public void begin() { //验证上一次是否请求完毕或者clear,否则抛出异常 assertNotCallingCallbacks(); //检查资源是否释放 stateVerifier.throwIfRecycled(); //计算开始时间 startTime = LogTime.getLogTime(); //判断图片加载途径是否为空,为空则抛出异常 if (model == null) { //判断宽高是否>0 if (Util.isValidDimensions(overrideWidth, overrideHeight)) { width = overrideWidth; height = overrideHeight; } int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG; onLoadFailed(new GlideException("Received null model"), logLevel); return; } //加载未完成 if (status == Status.RUNNING) { throw new IllegalArgumentException("Cannot restart a running request"); } //加载完成 if (status == Status.COMPLETE) { //检查资源是否存在,存在的话从内存中进行加载 onResourceReady(resource, DataSource.MEMORY_CACHE); return; } //设置加载状态 status = Status.WAITING_FOR_SIZE; if (Util.isValidDimensions(overrideWidth, overrideHeight)) { // 核心方法,如下 onSizeReady(overrideWidth, overrideHeight); } else { //在SizeDeterminer中重新进行尺寸测量 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)); } }
2、onSizeReady方法调整宽高
@Override public void onSizeReady(int width, int height) { ………………………………………………………………………省略部分代码…………………………………………………………………………………… //重新设置status状态 status = Status.RUNNING; //获取设置的转换因子(0-1)之间,防止图片过大或者加载略缩图 float sizeMultiplier = requestOptions.getSizeMultiplier(); //获取转换后的宽高值 this.width = maybeApplySizeMultiplier(width, sizeMultiplier); this.height = maybeApplySizeMultiplier(height, sizeMultiplier); //使用engine进行加载 loadStatus = engine.load( glideContext,//Glide上下文对象,详情查看上一篇文章 model,//请求地址URL、uri等等 requestOptions.getSignature(),//内存缓存和磁盘缓存的键 this.width, this.height, requestOptions.getResourceClass(),//Object的class对象 transcodeClass,//泛型参数,例如Bitmap,Drawable等 priority, //优先级 requestOptions.getDiskCacheStrategy(), //磁盘缓存的类型:枚举 requestOptions.getTransformations(), //动画集合:HashMap类型 requestOptions.isTransformationRequired(), //是否支持动画播放 requestOptions.isScaleOnlyOrNoTransform(), //是否支持缩放处理 requestOptions.getOptions(), //获取Options对象,Options是一个磁盘、内存缓存处理键的相关类 requestOptions.isMemoryCacheable(), //是否开启内存缓存 requestOptions.getUseUnlimitedSourceGeneratorsPool(), //true requestOptions.getUseAnimationPool(),开启无线内存缓存模式,该模式影响性能 requestOptions.getOnlyRetrieveFromCache(), //优先加载缓存资源 this); }
3、engine.load方法进行加载
engine类的初始化操作来自于上面讲的obtain方法,最终的结果来自于GlideContext类的getEngine()方法,关于该类详情请查看上一篇文章点击打开链接,engine类的load方法是根据跟定的参数进行加载,需要注意它必须是在主线程,省略部分代码:
public <R> LoadStatus load(………省略参数…) { //检查是否在主线程 Util.assertMainThread(); //根据当前参数生成内存缓存的key EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options); //1、从当前活跃的线程资源池中加载 EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) { cb.onResourceReady(active, DataSource.MEMORY_CACHE); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from active resources", startTime, key); } return null; } //2、从内存中加载 EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); if (cached != null) { cb.onResourceReady(cached, DataSource.MEMORY_CACHE); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from cache", startTime, key); } return null; } //3、从本地缓存中加载 EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); if (current != null) { current.addCallback(cb); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Added to existing load", startTime, key); } return new LoadStatus(cb, current); } //4、重新请求 EngineJob<R> engineJob = engineJobFactory.build( key, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache); ………………………………………………………………………省略部分代码…………………………………………………………………………………… return new LoadStatus(cb, engineJob); }
从上文中中可以看出他是经过四步进行加载的:
第一步:从当弱引用中加载
第二步:从内存中加载
第三步:从本地缓存中加载
第四步:从网络请求中加载
这四步,一旦有一步加载成功,就会设置设置资源加载成功或者异常的回调到onResourceReady方法,并且立即返回,不再进行接下来的加载,接下来分别看着四步请求过程。
四、加载的过程分析
上面说了图片的加载过程分为四步,前三步伴随着Glide的缓存加载的过程,也是Glide缓存机制的核心内容。这四步中需要用的一个键key,key的生成是EngineKey重写hashCode方法依据传递的参数生成的一个int类型的数据,除此之外还重写了equals方法,用于比较key是否为同一个。
1、从弱引用中加载
@Nullable private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) { //无内存缓存,则第一步加载失败,继续走第二步加载 if (!isMemoryCacheable) { return null; } //获取EngineResource,他是一个资源的包装类,用于资源的释放与获取 EngineResource<?> active = activeResources.get(key); if (active != null) { //进行资源释放,释放规则:用一个变量进行标记,如果当前引用一次则+1,释放一次则-1,有点像垃圾回收的算法 active.acquire(); } return active; }
深究activeResources.get(key)方法,会看到他的资源缓存机制,他是把资源放在一个HashMap集合中,集合的键为传递过来的key值为ResourceWeakReference弱引用,到这里才明白,第一步的加载过程本质上是从弱引用中加载资源。
@Nullable EngineResource<?> get(Key key) { ResourceWeakReference activeRef = activeEngineResources.get(key); if (activeRef == null) { return null; }
2、从内存中加载
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) { //无内存缓存,则第一步加载失败,继续走第二步加载 if (!isMemoryCacheable) { return null; } EngineResource<?> cached = getEngineResourceFromCache(key); if (cached != null) { //进行资源释放,释放规则:用一个变量进行标记,如果当前引用一次则+1,释放一次则-1,有点像垃圾回收的算法 cached.acquire(); //进行弱引用缓存,以保证第一步加载有数据,缓存的过程是保存在HashMap集合里面 activeResources.activate(key, cached); } return cached; }
getEngineResourceFromCache方法如下:
private EngineResource<?> getEngineResourceFromCache(Key key) { //根据key从MemoryCache移除之前的缓存,返回的值移除的缓存内容,可以为null Resource<?> cached = cache.remove(key); final EngineResource<?> result; if (cached == null) { //如果cached为null,则说明没有缓存,进行第三步加载 result = null; } else if (cached instanceof EngineResource) { //直接返回当前资源 result = (EngineResource<?>) cached; } else { //如果cached不属于EngineResource,则根据cached新建EngineResource,值接返回该对象 result = new EngineResource<>(cached, true /*isMemoryCacheable*/, true /*isRecyclable*/); } return result; }
3、从本地缓存中加载
//EngineJob加载资源或者移除资源的回调通知相关类, //key:缓存的键;onlyRetrieveFromCache:是否仅从磁盘缓存加载 EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); if (current != null) { //添加回调 current.addCallback(cb); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Added to existing load", startTime, key); } //后面看,先看第四步 return new LoadStatus(cb, current); }
4、从网络请求中加载
(1)获取engineJob对象:主要用来设置加载过程中监听回调。
EngineJob<R> engineJob = engineJobFactory.build( key, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache);
(2)获取decodeJob对象:主要是从缓存或者网络来的数据进行加载解析,他是一个Runnable实例对象,作为ExecutorService的参数。
DecodeJob<R> decodeJob = decodeJobFactory.build( glideContext, model, key, signature, width, height, resourceClass, transcodeClass, priority, diskCacheStrategy, transformations, isTransformationRequired, isScaleOnlyOrNoTransform, onlyRetrieveFromCache, options, engineJob);
(3)进行任务缓存
jobs.put(key, engineJob);
Jobs类中包含了两个HashMap集合,一个是jobs,另一个是onlyCacheJobs,使用哪个集合进行缓存是根据传递的参数进行选择:
private Map<Key, EngineJob<?>> getJobMap(boolean onlyRetrieveFromCache) { return onlyRetrieveFromCache ? onlyCacheJobs : jobs; }
(4)设置加载完成和加载失败回调
engineJob.addCallback(cb);
void addCallback(ResourceCallback cb) { Util.assertMainThread(); stateVerifier.throwIfRecycled(); if (hasResource) { //加载成功,设置资源加载成功的回调 cb.onResourceReady(engineResource, dataSource); } else if (hasLoadFailed) { //加载失败,设置资源加载失败的回调 cb.onLoadFailed(exception); } else { //否则添加到ResourceCallback集合 cbs.add(cb); }
(5)开启线程,开始执行加载
engineJob.start(decodeJob);
public void start(DecodeJob<R> decodeJob) { this.decodeJob = decodeJob; //返回true,则尝试在磁盘缓存中加载;返回false,则从网络资源获取 GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); //执行线程 executor.execute(decodeJob); }
(6)返回LoadStatus状态
return new LoadStatus(cb, engineJob);
接下来依据着五步进行网络请求加载分析。
五、网络请求的过程分析
在上面的第五步中开启线程,开始执行加载,可以看出执行线程操作的时候是在GlideExecutor类中,它实现了ExecutorService接口,操作Glide网络请求的线程调度。上一个(2)中提提到decodeJob是Runnable的实例对象,那么我们看看run方法的实现数据的加载:
@Override public void run() { TraceCompat.beginSection("DecodeJob#run"); DataFetcher<?> localFetcher = currentFetcher; try { if (isCancelled) { //true:表示取消加载了,通知加载失败 notifyFailed(); return; } //下面看看runWrapped方法 runWrapped(); } catch (Throwable t) { if (stage != Stage.ENCODE) { throwables.add(t); notifyFailed(); } if (!isCancelled) { throw t; } } finally { if (localFetcher != null) { localFetcher.cleanup(); } TraceCompat.endSection(); } }
private void runWrapped() { //一个枚举类型的数据,Why we're being executed again,包括如下三种类型: 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); } }
1、初始化阶段INITIALIZE
private Stage getNextStage(Stage current) { switch (current) { case INITIALIZE: //初始化需要执行的操作 //diskCacheStrategy:磁盘缓存 //Stage.RESOURCE_CACHE:从磁盘加载 //如果没有磁盘缓存,执行下一步,RESOURCE_CACHE 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: // 如果设置仅从磁盘加载省略过这一步 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); } }
2、磁盘缓存加载 SWITCH_TO_SOURCE_SERVICE
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; } } @Override public void reschedule() { runReason = RunReason.SWITCH_TO_SOURCE_SERVICE; callback.reschedule(this); }
3、开启线程网络加载DECODE_DATA
private void decodeFromRetrievedData() { Resource<R> 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(); } }
六、缓存机制分析
前一部分分析中涉及到Glide的缓存内容,但是没有着重进行讲解,关于缓存部分分为两大部分,内存缓存和磁盘缓存,在Glide的缓存部分中有两个涉及到缓存的API:skipMemoryCache、diskCacheStrategy分别表示是否跳过内存缓存和磁盘缓存策略设置,先来看看内存缓存。
1、缓存key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,resourceClass, transcodeClass, options);
从上面的方法可以看出,缓存key的生成需要的参数非常多,EngineKey实现了key接口,复写了equals,hashCode,toString,updateDiskCacheKey几个方法,众多的参数和比较方法的重写保证了key的唯一性,当任何一个参数变化,都会认为是不同的key。
2、内存缓存
requestOptions.skipMemoryCache(true);
(1)内存缓存策略
在上一篇文章中提到GlideBuilder这个类,在构建Glide的时候就会创建内存memoryCache对象:
if (memoryCache == null) { memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize()); }
现在就来看看内存缓存类LruResourceCache,他的继承关系:LruResourceCache -> LruCache 并且实现了MemoryCache接口。这说明Glide的内存缓存是依据LruCache算法为基础进行缓存的,这里不在分析LruCache算法。
(2)内存缓存大小
Glide中规定了内存缓存的大小为三类:低内存、正常内存、高内存,默认是正常内存,存在于MemoryCategory枚举中。
public enum MemoryCategory { LOW(0.5f), NORMAL(1f), HIGH(1.5f); }
通过trimMemory方法进行设置:
public void trimMemory(int level) { // Engine asserts this anyway when removing resources, fail faster and consistently Util.assertMainThread(); // memory cache needs to be trimmed before bitmap pool to trim re-pooled Bitmaps too. See #687. memoryCache.trimMemory(level); bitmapPool.trimMemory(level); arrayPool.trimMemory(level); }
(3)清除内存缓存
Glide.get(this).clearMemory();//需要在UI线程
3、磁盘缓存
requestOptions.diskCacheStrategy(DiskCacheStrategy.RESOURCE);
(1)磁盘缓存目录
在上一篇文章中说了,磁盘缓存路径是在Glide类中,默认缓存在CacheDir的"image_manager_disk_cache"文件夹下面,关于Glide类请查看上一篇文章。
(2)磁盘缓存策略
磁盘缓存使用的是DiskLruCache类,包括了五大缓存类型类型:ALL、NONE、DATA、RESOURCE、AUTOMATIC。
- DiskCacheStrategy.ALL 使用DATA和RESOURCE缓存远程数据,仅使用RESOURCE来缓存本地数据。
- DiskCacheStrategy.NONE 不使用磁盘缓存
- DiskCacheStrategy.DATA 在资源解码前就将原始数据写入磁盘缓存
- DiskCacheStrategy.RESOURCE 在资源解码后将数据写入磁盘缓存,即经过缩放等转换后的图片资源。
- DiskCacheStrategy.AUTOMATIC 根据原始图片数据和资源编码策略来自动选择磁盘缓存策略。
(3)清除磁盘缓存
Glide.get(MainActivity.this).clearDiskCache();//需要在子线程至此,Glide加载流程分析到此结束!