Glide加载流程分析(下)

    上一篇文章分析了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加载流程分析到此结束!



猜你喜欢

转载自blog.csdn.net/yoonerloop/article/details/79981049
今日推荐