Glide V4源码解析

本文的所有分析源码基于4.3.1版本。

相比于Glide V3版本,V4版本有较大的改进,代码上也进行了重构。V4版本采用了注解处理器为我们生成一个流式的Api,可以让开发者无缝的过渡到V4版本的使用,因为注解为我们生成的流式Api在使用上与V3版本基本完全相同。具体使用方法及介绍:Glide v4中文文档

1、概述



Glide是一个高度解耦、可扩展的高性能图片加载库。V4版本较之前有较大的重构,与V3相比,有如下需要注意点(不限):
1、Glide v4使用注解处理器 (Annotation Processor)来生成出一个API,在Application模块中可使用该流式API一次性调用到RequestBuilder,RequestOptions 和集成库中所有的选项。
2、thumbnail:允许你指定一个 RequestBuilder 以与你的主请求并行启动。
3、error:从 Glide4.3.0开始,你现在可以使用error API来指定一个RequestBuilder,以在主请求失败时开始一次新的加载。
4、fallback:在请求的url/model为 null 时展示。
5、不同于Glide v3,Glide v4将不会默认应用交叉淡入或任何其他的过渡效果。每个请求必须手动应用过渡。
6、在 Glide v3,默认的DecodeFormat是 DecodeFormat.PREFER_RGB_565。Glide V4现在默认使用ARGB_8888。
7、所有应用都必须添加一个AppGlideModule实现,即使应用并没有改变任何附加设置项,也没有实现 AppGlideModule中的任何方法。AppGlideModule 实现是一个信号,它会让 Glide 的注解解析器生成一个单一的所有已发现的 LibraryGlideModules 的联合类。
注意:AppGlideModule对应于我们的主项目,而LibraryGlideModules是用于类库项目的。对于一个特定的应用,只能存在一个 AppGlideModule 实现(超过一个会在编译时报错)。但是可以存在多个LibraryGlideModules。
示例:
@GlideModule
public final class MyAppGlideModule extends AppGlideModule {

  //个性化配置
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int memoryCacheSizeBytes = 1024 * 1024 * 20; // 20mb
    builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));
  }
  //应用程序和库都可以注册很多组件来扩展Glide的功能
  @Override
  public void registerComponents(Context context, Registry registry) {
  //注意这里是replace方法,意思是替换网络栈。这里是使用OkHttp作为底层的网络通信库
  //Glide已经为我们写好了如何使用OkHttp作为网络栈:compile "com.github.bumptech.glide:okhttp3-integration:4.3.0"
  //只要我们在build.gradle中配置了上述语句,我们就会引入一个已经写好的针对OkHttp的GlideMoudle
  //Glide会发现该Moudle(@GlideModule是一个信号),并将OkHttp作为底层的网络通信库
  //注意:在Registry类中定义了prepend(), append()和 replace()方法,具体区别可以看一下官方文档
    registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
  }

  @Override
  public boolean isManifestParsingEnabled() {
  //如果你直接使用的V4,建议重写该方法,返回false。避免再次解析Manifest了。
  //因为V4现在采用了注解的方式,而不是之前的在Manifest中配置。
    return false;
  }
}
8、应用程序和库都可以注册很多组件来扩展Glide的功能。这里看出了Glide的高度可扩展性。

2、目标

本文的主要目标是通过阅读源码解决如下三个问题:
1、解决Glide.with(..).load(...).into(..);这段既熟悉又陌生的背后执行逻辑,分析Glide的整体的执行流程;
2、Glide与Activity/Fragment生命周期绑定是怎么做到的?
3、Glide的多级缓存;
4、Glide的下采样;

3、准备

Glide中有几个比较重要的类需要提前了解一下,这样看后面的源码会比较容易一些:

--------------------英文注释自行品尝---------------------------------
RequestOptions:Glide中的大部分设置项都可以通过 RequestOptions 类和 apply() 方法来应用到程序中。
使用request options可以实现(包括但不限于):
a)占位符(Placeholders);
b)转换(Transformations);
c)缓存策略(Caching Strategies);
d)组件特有的设置项,例如编码质量,或Bitmap的解码配置等。
RequestManagerRetriever:该类有一系列的静态方法用于创建新的Requestmanager或者获取Activity/Fragment中已经存在的RequestManager.

RequestManager:A class for managing and starting requests for Glide. Can use activity, fragment and connectivity  lifecycle events to intelligently stop, start, and restart requests. Retrieve either by  instantiating a new object, or to take advantage built in Activity and Fragment lifecycle handling, use the static Glide.load methods with your Fragment or Activity。

RequestBuilder:Glide中请求的骨架,负责携带请求的url和你的设置项来开始一个新的加载过程。

SingleRequest:A Request that loads a Resource into a given Target.

Target: 介于请求和请求者之间的中介者的角色。Target 负责展示占位符,加载资源,并为每个请求决定合适的尺寸。

Engine:Responsible for starting loads and managing active and cached resources.

4、源码分析

Glide.with(..).load(...).into(..);该行代码是我们分析的主线,来分析一个String类型的地址是如何完成请求的。

4.1 with(...) - Glide

public static RequestManager with(Activity activity) {
    return getRetriever(activity).get(activity);
  }
可以看到为了得到一个RequestManager,需要两步完成,第一步RequestManagerRetriever,第二步通过RequestManagerRetriever获取RequestManager。
第一步:
  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    ......
    return Glide.get(context).getRequestManagerRetriever();
  }

Glide.get(context)是Glide提供的通过单利模式获取Glide实例的方法:

  public static Glide get(Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context);
        }
      }
    }
    return glide;
  }
典型的双重校验单利模式。最终会调用如下方法:
 private static void initializeGlide(Context context) {
    Context applicationContext = context.getApplicationContext();
    //获取我们的@GlideModule AppGlideModule实例
    GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
    //manifestModules:Manifest中配置的Module(v3的做法)
    List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
    //在AppGlideModule中重写isManifestParsingEnabled方法,返回false可以避免再次解析Manifest。
    //当然如果你使用的V3版本,则没必要重写这个方法。为了兼容V3,V4在这里还是做了判断
    if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
      manifestModules = new ManifestParser(applicationContext).parse();
    }
    //去除AppGlideModule(V4)中@Excludes的Module(兼容V3中Manifest中配置的Moudle)。
    if (annotationGeneratedModule != null
        && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
      Set<Class<?>> excludedModuleClasses =
          annotationGeneratedModule.getExcludedModuleClasses();
      Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
      while (iterator.hasNext()) {
        com.bumptech.glide.module.GlideModule current = iterator.next();
        if (!excludedModuleClasses.contains(current.getClass())) {
          continue;
        }
        
        iterator.remove();
      }
    }

    RequestManagerRetriever.RequestManagerFactory factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManagerFactory() : null;//Glide的annotationGlide(GlideModule)为我们生成了RequestManager
    GlideBuilder builder = new GlideBuilder()
        .setRequestManagerFactory(factory);//设置RequestManagerFactory
    //应用个性化配置到Glide中(V3),比如缓存大小
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      module.applyOptions(applicationContext, builder);
    }
    //应用个性化配置到Glide中(V4),比如缓存大小
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.applyOptions(applicationContext, builder);
    }
    //build一个Glide实例
    Glide glide = builder.build(applicationContext);
    //V3:应用程序和库都可以注册很多组件来扩展Glide的功能
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      module.registerComponents(applicationContext, glide, glide.registry);
    }
    //v4:应用程序和库都可以注册很多组件来扩展Glide的功能
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    }
    context.getApplicationContext().registerComponentCallbacks(glide);
    Glide.glide = glide;
  }
上述源码中,最重要的是这一句代码:Glide glide = builder.build(applicationContext);这行代码完成了Glide的实例化,同时我们需要的RequestManagerRetriever也在build方法中设置给了Glide:
 ...
    RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(
        requestManagerFactory);
    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions);
其余的代码都是为初始化做的准备:应用用户个性化option、兼容V3、支持Glide的高扩展性。Glide实例化会初始化各种pool、缓存、以及注册组件。Glide实例化的代码还是很多的,感兴趣的可以阅读一下(想要了解实例化的时候做了哪些工作,还是有必要阅读一下的)。
到此处,通过Glide.get(context).getRequestManagerRetriever();我们就得到了需要的RequestManagerRetriever。
public static RequestManager with(Activity activity) {
    return getRetriever(activity).get(activity);
  }
下面分析第二步:通过获取RequestManagerRetriever获取RequestManager。这个地方可以解决“Glide与Activity/Fragment生命周期绑定是怎么做到的?”的问题。
  public RequestManager get(Activity activity) {
    if (Util.isOnBackgroundThread()) {//判断是否是后台运行
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();//Activity的FragmentManager
      return fragmentGet(activity, fm, null /*parentHint*/);
    }
  }
继续看fragmentGet的源码:
private RequestManager fragmentGet(Context context, android.app.FragmentManager fm,
      android.app.Fragment parentHint) {
    //获取RequestManagerFragment
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
    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);
      //为RequestManagerFragment设置RequestManager
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
可以看到在获取到RequestManager之前,我们必须先获取RequestManagerFragment,继续看getRequestManagerFragment(...)的源码:
 RequestManagerFragment getRequestManagerFragment(
      final android.app.FragmentManager fm, android.app.Fragment parentHint) {
    //通过Activity的FragmentManager查找Fragment
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        pendingRequestManagerFragments.put(fm, current);
        //将Fragment添加到FragmentManager中
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }
看到这里你是否已经想到了“Glide与Activity/Fragment生命周期绑定是怎么做到的?”这个问题Glide是怎么解决的?Glide给出的方案是生成一个隐藏的Fragment,并将其添加到Activity的FragmentManager中,这样就可以绑定到Activity的生命周期了。该隐藏的Fragment通过其onAttach、onDetach、onstart、onStop、onDestroy等生命周期方法再进行相应的操作。
得到了RequestManagerFragment之后,通过RequestManagerFactory生成RequestManager,设置给RequestManagerFragment,并返回该RequestManager。

4.2、load(...) - RequestManager

with(...)的流程最终生成了一个RequestManager,很自然的,load(...)是RequestManager的一个方法。
public RequestBuilder<Drawable> load(@Nullable Object model) {
    return asDrawable().load(model);
  }
asDrawable会生成一个RequestBuilder,其实RequestManager的load方法最终调用的是RequestBuilder的load方法。
  @CheckResult
  @SuppressWarnings("unchecked")
  public RequestBuilder<TranscodeType> load(@Nullable Object model) {
    return loadGeneric(model);
  }

  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }
此处的Model就是我们请求的地址的String串。RequestBuilder会记住这个Model,同时继续向后执行。

4.3 into(imageView) - RequestBuilder

into方法主要作用如下:Sets the ImageView the resource will be loaded into, cancels any existing loads into the view, and frees any resources Glide may have previously loaded into the view so they may be reused.
 public Target<TranscodeType> into(ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    RequestOptions requestOptions = this.requestOptions;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      // Clone in this method so that if we use this RequestBuilder to load into a View and then
      // into a different target, we don't retain the transformation applied based on the previous
      // View's scale type.
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions = requestOptions.clone().optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions = requestOptions.clone().optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }

    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions);
  }
上述switch语句是不是很熟悉的感觉,此处涉及到了Glide下采样的算法执行策略。最终,该方法会调用另外一个into方法。
private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      RequestOptions options) {
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    options = options.autoClone();
    //构建Request对象
    Request request = buildRequest(target, targetListener, options);
    //target:Glide为我们构建的ImageViewTarget对象
    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)) {//如果target的Request与当前新构建的Request相同,则重用
      request.recycle();
      // If the request is completed, beginning again will ensure the result is re-delivered,
      // triggering RequestListeners and Targets. If the request is failed, beginning again will
      // restart the request, giving it another chance to complete. If the request is already
      // running, we can let it continue running without interruption.
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        // Use the previous request rather than the new one to allow for optimizations like skipping
        // setting placeholders, tracking and untracking Targets, and obtaining View dimensions that
        // are done in the individual Request.
        previous.begin();
      }
      return target;
    }
    //否则,就将新构建的request设置给target,同时由requestManager负责监督request的执行过程
    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }
可以看到request的重用。否则,新构建的Request将交给RequestManager来监督request的执行。
上述最重要的是buildRequest(...)这行代码:
-------------------------------------------------buildRequest(...)分析开始---------------------------------------------------------
private Request buildRequest(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      RequestOptions requestOptions) {
    return buildRequestRecursive(
        target,
        targetListener,
        /*parentCoordinator=*/ null,
        transitionOptions,
        requestOptions.getPriority(),
        requestOptions.getOverrideWidth(),
        requestOptions.getOverrideHeight(),
        requestOptions);
  }
 private Request buildRequestRecursive(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) {

    // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
    ErrorRequestCoordinator errorRequestCoordinator = null;
    //v4支持为error方法设置requestBuilder,也就是此处的errorBuilder
    if (errorBuilder != null) {
      errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }

    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions);
    //如果没有设置errorBuilder,则直接返回这个正常的请求
    if (errorRequestCoordinator == null) {
      return mainRequest;
    }

    int errorOverrideWidth = errorBuilder.requestOptions.getOverrideWidth();
    int errorOverrideHeight = errorBuilder.requestOptions.getOverrideHeight();
    //如果我们主动使用了overrider方法重写了请求的图片的宽度和高度
    //则需要将其设置给errorBuilder用于构建errorRequest
    if (Util.isValidDimensions(overrideWidth, overrideHeight)
        && !errorBuilder.requestOptions.isValidOverride()) {
      errorOverrideWidth = requestOptions.getOverrideWidth();
      errorOverrideHeight = requestOptions.getOverrideHeight();
    }
   //如果设置了errorBuilder,则构建一个errorRequest
    Request errorRequest = errorBuilder.buildRequestRecursive(
        target,
        targetListener,
        errorRequestCoordinator,
        errorBuilder.transitionOptions,
        errorBuilder.requestOptions.getPriority(),
        errorOverrideWidth,
        errorOverrideHeight,
        errorBuilder.requestOptions);
    //ErrorRequestCoordinator:此类的作用就是如果mainRequest执行失败,则执行errorRequest
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }
以上源码,我已经加了注释。下面分析一下:
如果我们在正常请求的同时,设置了一个error(RequstBuilder),那么执行流程将会是:先执行mainRequest,如果mainRequest执行失败,则执行errorRequest,这验证了我们概述中的第三条。那么一个正常的请求包含哪些部分呢?
private Request buildThumbnailRequestRecursive(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) {
    if (thumbnailBuilder != null) {
      // Recursive case: contains a potentially recursive thumbnail request builder.
      if (isThumbnailBuilt) {
        throw new IllegalStateException("You cannot use a request as both the main request and a "
            + "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
      }

      TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
          thumbnailBuilder.transitionOptions;

      // Apply our transition by default to thumbnail requests but avoid overriding custom options
      // that may have been applied on the thumbnail request explicitly.
      if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
        thumbTransitionOptions = transitionOptions;
      }

      Priority thumbPriority = thumbnailBuilder.requestOptions.isPrioritySet()
          ? thumbnailBuilder.requestOptions.getPriority() : getThumbnailPriority(priority);

      int thumbOverrideWidth = thumbnailBuilder.requestOptions.getOverrideWidth();
      int thumbOverrideHeight = thumbnailBuilder.requestOptions.getOverrideHeight();
      if (Util.isValidDimensions(overrideWidth, overrideHeight)
          && !thumbnailBuilder.requestOptions.isValidOverride()) {
        thumbOverrideWidth = requestOptions.getOverrideWidth();
        thumbOverrideHeight = requestOptions.getOverrideHeight();
      }

      ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
      Request fullRequest =
          obtainRequest(
              target,
              targetListener,
              requestOptions,
              coordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight);
      isThumbnailBuilt = true;
      // Recursively generate thumbnail requests.
      Request thumbRequest =
          thumbnailBuilder.buildRequestRecursive(
              target,
              targetListener,
              coordinator,
              thumbTransitionOptions,
              thumbPriority,
              thumbOverrideWidth,
              thumbOverrideHeight,
              thumbnailBuilder.requestOptions);
      isThumbnailBuilt = false;
      coordinator.setRequests(fullRequest, thumbRequest);
      return coordinator;
    } else if (thumbSizeMultiplier != null) {
      // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
      ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
      Request fullRequest =
          obtainRequest(
              target,
              targetListener,
              requestOptions,
              coordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight);
      RequestOptions thumbnailOptions = requestOptions.clone()
          .sizeMultiplier(thumbSizeMultiplier);

      Request thumbnailRequest =
          obtainRequest(
              target,
              targetListener,
              thumbnailOptions,
              coordinator,
              transitionOptions,
              getThumbnailPriority(priority),
              overrideWidth,
              overrideHeight);

      coordinator.setRequests(fullRequest, thumbnailRequest);
      return coordinator;
    } else {
      // Base case: no thumbnail.
      return obtainRequest(
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight);
    }
  }
可以看到,如果我们设置了thumbnail(RequestBuilder),则会返回一个ThumbnailRequestCoordinator对象(request子类),该对象包裹了图片资源请求(fullRequst)和缩略图请求(thumbnailRequest),与error(RequestBuilder不同),fullRequst和thumbnailRequest会并行执行。这验证了概述中的第二条。
如果没有thumbnail请求,则只通过obtainRequest获取图片资源的请求即可。其实无论是fullRequst还是thumbnailRequest,最终都是通过如下的obtainRequest方法获取到最终的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) {
    //从POOL中获取一个Request
    @SuppressWarnings("unchecked") SingleRequest<R> request =
        (SingleRequest<R>) POOL.acquire();
    //如果没有获取到,就实例化一个
    if (request == null) {
      request = new SingleRequest<>();
    }
    request.init(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListener,
        requestCoordinator,
        engine,
        animationFactory);
    return request;
  }
可以看到,如果需要一个Request,Glide会首先去POOL中获取,如果获取不到,才会去创建一个新的Request。那么,这个POOL到底是一个怎样的数据结构呢?
private static final Pools.Pool<SingleRequest<?>> POOL = FactoryPools.simple(150,
      new FactoryPools.Factory<SingleRequest<?>>() {
        @Override
        public SingleRequest<?> create() {
          return new SingleRequest<Object>();
        }
      });
在SingleRequest类中,会初始化一个这样的变量POOL,它是Android提供的一个池类。里面只有三个方法:acquire、release、isInPool
public static class SimplePool<T> implements Pool<T> {
        private final Object[] mPool;

        private int mPoolSize;

        /**
         * Creates a new instance.
         *
         * @param maxPoolSize The max pool size.
         *
         * @throws IllegalArgumentException If the max pool size is less than zero.
         */
        public SimplePool(int maxPoolSize) {
            if (maxPoolSize <= 0) {
                throw new IllegalArgumentException("The max pool size must be > 0");
            }
            mPool = new Object[maxPoolSize];
        }

        @Override
        @SuppressWarnings("unchecked")
        public T acquire() {
            if (mPoolSize > 0) {
                final int lastPooledIndex = mPoolSize - 1;
                T instance = (T) mPool[lastPooledIndex];
                mPool[lastPooledIndex] = null;
                mPoolSize--;
                return instance;
            }
            return null;
        }

        @Override
        public boolean release(T instance) {
            if (isInPool(instance)) {
                throw new IllegalStateException("Already in the pool!");
            }
            if (mPoolSize < mPool.length) {
                mPool[mPoolSize] = instance;
                mPoolSize++;
                return true;
            }
            return false;
        }

        private boolean isInPool(T instance) {
            for (int i = 0; i < mPoolSize; i++) {
                if (mPool[i] == instance) {
                    return true;
                }
            }
            return false;
        }
    }
Glide会首先给我们在池中实例化150个request对象,除非请求数超过150个。否则,Glide会直接从POOL中取出一个Request对象。
acquire:从池中获取一个Request对象,同时,mPoolSize减一;
release:将使用完的Request对象重新放入池中,mPoolSize加一;
isInPool:判断是否在池中;
Glide的这种做法无疑是提高了性能,加快了请求的速度;
-------------------------------------------------buildRequest(...)分析结束---------------------------------------------------------
由以上分析,我们可以得到,最终的Request都是一个SingleRequest对象。回到into(..)方法继续分析,如果不存在一个可复用的Request,则新构建的Request会被交给RequestManager监督执行:
target.setRequest(request);
requestManager.track(target, request);
RequestManager的track方法:
 void track(Target<?> target, Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }
继续:
 public void runRequest(Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      pendingRequests.add(request);
    }
  }
可以看到,除了当前处于暂停状态,否则就会调用SingleRequest的begin()方法开始执行Request.
  @Override
  public void begin() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    //model在这里就是我们请求的地址,一般不会为null
    if (model == null) {
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        width = overrideWidth;
        height = overrideHeight;
      }
      // Only log at more verbose log levels if the user has set a fallback drawable, because
      // fallback Drawables indicate the user expects null models occasionally.
      int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
      onLoadFailed(new GlideException("Received null model"), logLevel);
      return;
    }
    //不能使用一个正在使用的Request
    if (status == Status.RUNNING) {
      throw new IllegalArgumentException("Cannot restart a running request");
    }

    // If we're restarted after we're complete (usually via something like a notifyDataSetChanged
    // that starts an identical request into the same Target or View), we can simply use the
    // resource and size we retrieved the last time around and skip obtaining a new size, starting a
    // new load etc. This does mean that users who want to restart a load because they expect that
    // the view size has changed will need to explicitly clear the View or Target before starting
    // the new load.
    if (status == Status.COMPLETE) {
      onResourceReady(resource, DataSource.MEMORY_CACHE);
      return;
    }

    // Restarts for requests that are neither complete nor running can be treated as new requests
    // and can run again from the beginning.

    status = Status.WAITING_FOR_SIZE;
    //如果我们重写了请求的尺寸,则直接调用onSizeReady。否则,通过Target来计算大小
    //即Glide自动为我们计算一个合适的ImageView大小
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      //这里体现了Target的作用之一:为每个请求决定合适的尺寸
      target.getSize(this);
    }

    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      //请求正在进行或者Glide正在计算ImageView尺寸
      target.onLoadStarted(getPlaceholderDrawable());
    }
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
  }
在正式开始一个请求之前,Glide会帮我们计算需要请求的图片的合适尺寸。当然,如果重写了override方法则Glide不会再去计算。对于ImageView,使用的是ImageViewTarget
以下是ImageViewTarget的getSize方法:
void getSize(SizeReadyCallback cb) {
      int currentWidth = getTargetWidth();//目标宽度
      int currentHeight = getTargetHeight();//目标高度
      if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
        cb.onSizeReady(currentWidth, currentHeight);//回调SingleRequest的onSizeReady方法
        return;
      }

      // We want to notify callbacks in the order they were added and we only expect one or two
      // callbacks to be added a time, so a List is a reasonable choice.
      if (!cbs.contains(cb)) {
        cbs.add(cb);
      }
      if (layoutListener == null) {
        ViewTreeObserver observer = view.getViewTreeObserver();
        layoutListener = new SizeDeterminerLayoutListener(this);
        observer.addOnPreDrawListener(layoutListener);
      }
    }
拿到合适的尺寸之后,ImageViewTarget就会回调SingleRequest的onSizeReady方法。在onSizeReady方法中,通过Engine开始正式的发起请求:
 @Override
  public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
    if (status != Status.WAITING_FOR_SIZE) {
      return;
    }
    status = Status.RUNNING;

    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
    }
    loadStatus = engine.load(//关键方法
        glideContext,
        model,
        requestOptions.getSignature(),
        this.width,
        this.height,
        requestOptions.getResourceClass(),
        transcodeClass,
        priority,
        requestOptions.getDiskCacheStrategy(),
        requestOptions.getTransformations(),
        requestOptions.isTransformationRequired(),
        requestOptions.isScaleOnlyOrNoTransform(),
        requestOptions.getOptions(),
        requestOptions.isMemoryCacheable(),
        requestOptions.getUseUnlimitedSourceGeneratorsPool(),
        requestOptions.getUseAnimationPool(),
        requestOptions.getOnlyRetrieveFromCache(),
        this);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
  }
接着看load中到底发生了什么?
 public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean useAnimationPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb) {
    Util.assertMainThread();
    long startTime = LogTime.getLogTime();
    //构建缓存的Key
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
   //从缓存中查找资源
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      //说明有缓存可用,返回。并回调SingleRequest的onResourceReady方法
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }
    //如果缓存中没有,则从另一级缓存【正在使用的缓存集合】中取
    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;
    }
    //EngineJob的任务是非常繁重的,Engine也是主要通过该类来完成数据的请求或获取
    EngineJob<?> current = jobs.get(key);
    if (current != null) {
      current.addCallback(cb);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }
    //流程走到这一步,主要的工作就是:从磁盘缓存中取数据 Or 网络请求
    EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
        useUnlimitedSourceExecutorPool, useAnimationPool);
    //DecodeJob主要负责将取到的数据(缓存或者网络数据)解析出来
    DecodeJob<R> decodeJob = decodeJobFactory.build(
        glideContext,
        model,
        key,
        signature,
        width,
        height,
        resourceClass,
        transcodeClass,
        priority,
        diskCacheStrategy,
        transformations,
        isTransformationRequired,
        isScaleOnlyOrNoTransform,
        onlyRetrieveFromCache,
        options,
        engineJob);
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);
    engineJob.start(decodeJob);

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
  }
此处,可以看出Glide的多级缓存的执行(读取)流程:
内存缓存 (Memory Cache[LruCache{基于LinkHashMap}]->Active Resource[Map -缓存正在使用的资源 ])--> 磁盘缓存(DataCache、SourceCache)
如果在Memory Cache中存在,则取出。然后将其存在Active Resource中。
在上述缓存中,仍然没有取到需要的数据,则从网络加载数据。
而写入流程:
 磁盘缓存 - > Active Resource - > Memory Cache。
当通过网络拿到数据后,先判断是否支持本地磁盘缓存,如果支持,则将其缓存到磁盘中。如果该条数据被使用,则将其缓存到Active Resource中。不再使用了,则将其缓存的Memory Cache中,
在Glide V4中,磁盘缓存的默认执行策略是:AUTOMATIC.
默认的策略叫做 AUTOMATIC ,它会尝试对本地和远程图片使用最佳的策略。当你加载远程数据(比如,从URL下载)时,AUTOMATIC 策略仅会存储未被你的加载过程修改过(比如,变换,裁剪–译者注)的原始数据,因为下载远程数据相比调整磁盘上已经存在的数据要昂贵得多。对于本地数据,AUTOMATIC 策略则会仅存储变换过的缩略图,因为即使你需要再次生成另一个尺寸或类型的图片,取回原始数据也很容易。
---------关于如何从磁盘、网络取数据,不再分析(源码量还是蛮多的~~)只需知道整体的流程就可以了(困了~~)
与磁盘缓存关系较大的类是DiskLruCache。与Glide网络通信相关的是:HttpUrlFetcher,该类的关键的方法:
 private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
      Map<String, String> headers) throws IOException {
    if (redirects >= MAXIMUM_REDIRECTS) {
      throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
    } else {
      // Comparing the URLs using .equals performs additional network I/O and is generally broken.
      // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
      try {
        if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
          throw new HttpException("In re-direct loop");

        }
      } catch (URISyntaxException e) {
        // Do nothing, this is best effort.
      }
    }

    urlConnection = connectionFactory.build(url);
    for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
    urlConnection.setConnectTimeout(timeout);
    urlConnection.setReadTimeout(timeout);
    urlConnection.setUseCaches(false);
    urlConnection.setDoInput(true);

    // Stop the urlConnection instance of HttpUrlConnection from following redirects so that
    // redirects will be handled by recursive calls to this method, loadDataWithRedirects.
    urlConnection.setInstanceFollowRedirects(false);

    // Connect explicitly to avoid errors in decoders if connection fails.
    urlConnection.connect();
    // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
    stream = urlConnection.getInputStream();
    if (isCancelled) {
      return null;
    }
    final int statusCode = urlConnection.getResponseCode();
    if (statusCode / 100 == 2) {
      return getStreamForSuccessfulRequest(urlConnection);
    } else if (statusCode / 100 == 3) {
      String redirectUrlString = urlConnection.getHeaderField("Location");
      if (TextUtils.isEmpty(redirectUrlString)) {
        throw new HttpException("Received empty or null redirect url");
      }
      URL redirectUrl = new URL(url, redirectUrlString);
      // Closing the stream specifically is required to avoid leaking ResponseBodys in addition
      // to disconnecting the url connection below. See #2352.
      cleanup();
      return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
    } else if (statusCode == -1) {
      throw new HttpException(statusCode);
    } else {
      throw new HttpException(urlConnection.getResponseMessage(), statusCode);
    }
  }
可以看到Glide默认使用HttpUrlConnection。

4.4、下采样

Glide中使用DownSampler类实现重采样。其实现的方式是采用BitmapFactory。
 private static int[] getDimensions(InputStream is, BitmapFactory.Options options,
      DecodeCallbacks decodeCallbacks, BitmapPool bitmapPool) throws IOException {
    options.inJustDecodeBounds = true;
    decodeStream(is, options, decodeCallbacks, bitmapPool);
    options.inJustDecodeBounds = false;
    return new int[] { options.outWidth, options.outHeight };
  }
将inJustDecodeBounds设置为true,则BitmapFactory可以在不解析资源的情况下,获取资源的基本信息。但是,注意在真正的解析之前,一定要把该属性在设置为false。知道资源的基本信息(寛高等),则就可以计算采样率了。最后再解析图片。

5、总结

本文只是从源码的角度简单的分析了Glide V4整体的执行流程,作为学习备份使用。由于能力有限,难免出现错误。不得不说,Glide的代码量真是庞大。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值