Gilde的源码学习

在大多数的时候使用Gilde只用一行代码:

Glide.with(this).load(url).into(imageView);

对于源码学习,一开始喜欢逐行逐句的去看,后来发现自己非常容易陷入其中,其实只需要我们从常用的功能点入手去分析,明白主题逻辑就够了
本文是基于4.0.0学习分析的

第一个方法with()
这是Gilde类提供的一组静态方法,有多个重载的方法

public static RequestManager with(Context context) {
    return getRetriever(context).get(context);
  }

  /**
   * Begin a load with Glide that will be tied to the given {@link android.app.Activity}'s lifecycle
   * and that uses the given {@link Activity}'s default options.
   *
   * @param activity The activity to use.
   * @return A RequestManager for the given activity that can be used to start a load.
   */
  public static RequestManager with(Activity activity) {
    return getRetriever(activity).get(activity);
  }

  /**
   * Begin a load with Glide that will tied to the give
   * {@link android.support.v4.app.FragmentActivity}'s lifecycle and that uses the given
   * {@link android.support.v4.app.FragmentActivity}'s default options.
   *
   * @param activity The activity to use.
   * @return A RequestManager for the given FragmentActivity that can be used to start a load.
   */
  public static RequestManager with(FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

  /**
   * Begin a load with Glide that will be tied to the given {@link android.app.Fragment}'s lifecycle
   * and that uses the given {@link android.app.Fragment}'s default options.
   *
   * @param fragment The fragment to use.
   * @return A RequestManager for the given Fragment that can be used to start a load.
   */
  public static RequestManager with(android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }

  /**
   * Begin a load with Glide that will be tied to the given
   * {@link android.support.v4.app.Fragment}'s lifecycle and that uses the given
   * {@link android.support.v4.app.Fragment}'s default options.
   *
   * @param fragment The fragment to use.
   * @return A RequestManager for the given Fragment that can be used to start a load.
   */
  public static RequestManager with(Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }

可以看到重载的种类非常多,参数可以传入Context,Activity,fragment,fragmentActivity等,方法也是很简单:getRetriever()获取了RequestManagerRetriever对象,再通过get()方法获取了RequestManager ()对象,
下面分析一下getRetriever()方法干了什么

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    // Context could be null for other reasons (ie the user passes in null), but in practice it will
    // only occur due to errors with the Fragment lifecycle.
    Preconditions.checkNotNull(
        context,
        "You cannot start a load on a not yet attached View or a  Fragment where getActivity() "
            + "returns null (which usually occurs when getActivity() is called before the Fragment "
            + "is attached or after the Fragment is destroyed).");
    return Glide.get(context).getRequestManagerRetriever();
  }

首先检查了context的传入是否为空,若为空则抛出异常,接下来获取Glide实例并去获取RequestManagerRetriever实例
接下来再来分析一下RequestManagerRetriever的get()方法干了啥

 public RequestManager get(Context context) {                                                                      
   if (context == null) {                                                                                          
     throw new IllegalArgumentException("You cannot start a load on a null Context");                              
   } else if (Util.isOnMainThread() && !(context instanceof Application)) {                                        
     if (context instanceof FragmentActivity) {                                                                    
       return get((FragmentActivity) context);                                                                     
     } else if (context instanceof Activity) {                                                                     
       return get((Activity) context);                                                                             
     } else if (context instanceof ContextWrapper) {                                                               
       return get(((ContextWrapper) context).getBaseContext());                                                    
     }                                                                                                             
   }                                                                                                               
                                                                                                                   
   return getApplicationManager(context);                                                                          
 }                                                                                                                 
                                                                                                                   
 public RequestManager get(FragmentActivity activity) {                                                            
   if (Util.isOnBackgroundThread()) {                                                                              
     return get(activity.getApplicationContext());                                                                 
   } else {                                                                                                        
     assertNotDestroyed(activity);                                                                                 
     FragmentManager fm = activity.getSupportFragmentManager();                                                    
     return supportFragmentGet(activity, fm, null /*parentHint*/);                                                 
   }                                                                                                               
 }                                                                                                                 
                                                                                                                   
 public RequestManager get(Fragment fragment) {                                                                    
   Preconditions.checkNotNull(fragment.getActivity(),                                                              
         "You cannot start a load on a fragment before it is attached or after it is destroyed");                  
   if (Util.isOnBackgroundThread()) {                                                                              
     return get(fragment.getActivity().getApplicationContext());                                                   
   } else {                                                                                                        
     FragmentManager fm = fragment.getChildFragmentManager();                                                      
     return supportFragmentGet(fragment.getActivity(), fm, fragment);                                              
   }                                                                                                               
 }                                                                                                                 
                                                                                                                   
 public RequestManager get(Activity activity) {                                                                    
   if (Util.isOnBackgroundThread()) {                                                                              
     return get(activity.getApplicationContext());                                                                 
   } else {                                                                                                        
     assertNotDestroyed(activity);                                                                                 
     android.app.FragmentManager fm = activity.getFragmentManager();                                               
     return fragmentGet(activity, fm, null /*parentHint*/);                                                        
   }                                                                                                               
 }                                                                                                                 
                                                                                                                   
 public RequestManager get(View view) {                                                                            
   if (Util.isOnBackgroundThread()) {                                                                              
     return get(view.getContext().getApplicationContext());                                                        
   }                                                                                                               

可以看到这也是一组重载方法,看上去有好多个参数,实际上只要分清楚是Application和非Application就行,
我们先看Application的情况,如果在Glide.with()方法中传入的是一个Application对象,那么这里就会调用带有Context参数的get()方法重载,然后getApplicationManager()方法来获取一个RequestManager对象。其实这是最简单的一种情况,因为Application对象的生命周期即应用程序的生命周期,因此Glide并不需要做什么特殊的处理,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide的加载也会同时终止。
接下来我们看传入非Application参数的情况。不管你在Glide.with()方法中传入的是Activity、FragmentActivity、v4包下的Fragment、还是app包下的Fragment,最终的流程都是一样的,那就是会向当前的Activity当中添加一个隐藏的没有视图的Fragment,通过与fragment的生命周期进行关联进而实现组件的生命周期的实现,
另外如果我们是在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理
总结:
Glide:初始化各个组件的使用入口
RequestManagerRetriever
是用来创建并从activity和fragment中检索已存在的RequestManager;
RequestManagerFragment
没有视图的fragment,简单的来讲,就是在每一个Activity或者Fragment上又添加了一个Fragment,该Fragment没有View,仅仅用来存储RequestManager并管理Glide请求
Request Manager
通过 ActivityFragmentLifecycle 的 addListener 方法注册 LifecycleListener。当 RequestManagerFragment 生命周期方法执行的时候,触发 ActivityFragmentLifecycle 的相应方法,然后会遍历所有注册的 LifecycleListener 并执行相应生命周期方法。这样就完成了生命周期和Glide的request请求的完整关联。

总体来说,第一个with()方法的源码还是比较好理解的。其实就是为了得到一个RequestManager对象而已,然后Glide会根据我们传入with()方法的参数来确定图片加载的生命周期

第二个方法load()
由于with方法返回的是一个RequestManager的对象,接下来的这个方法肯定是在RequestManager类中,只有一个方法,与3.7.0不同没有那么多的重载方法:

 public RequestBuilder load(@Nullable Object model) {
    return asDrawable().load(model);
  }

public RequestBuilder asDrawable() {
    return as(Drawable.class).transition(new DrawableTransitionOptions());
  }

创建一个RequestBuilder,并添加一个过场动画

 public RequestBuilder load(@Nullable Object model) {
    return loadGeneric(model);
  }

  private RequestBuilder loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }

这一步没有什么内容,都是在给requestBuilder参数赋值,并返回一个对象为下一步做准备

第三个方法into()
with返回的是RequestManger的对象
load返回的是RequestBuilder的对象
into返回的是Target的对象

public Target into(ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      if (requestOptions.isLocked()) {
        requestOptions = requestOptions.clone();
      }
      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.
      }
    }

    return into(context.buildImageViewTarget(view, transcodeClass));

首先Util.assertMainThread();判断是否是在主线程,如果不是抛出异常,
然后Preconditions.checkNotNull(view);判断view是否为空,若为空则抛出异常,通过判断view的scaleType设置图片的加载形式

public  Target buildImageViewTarget(ImageView imageView, Class transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
  }

这里其实又是调用了ImageViewTargetFactory的buildTarget()方法,我们继续跟进去,代码如下所示:

public  Target buildTarget(ImageView view, Class clazz) {
    if (Bitmap.class.equals(clazz)) {
      return (Target) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      return (Target) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }

可以看到,在buildTarget()方法中会根据传入的class参数来构建不同的Target对象,这个class参数其实基本上只有两种情况,如果你在使用Glide加载图片的时候调用了asBitmap()方法,那么这里就会构建出BitmapImageViewTarget对象,否则的话构建的都是GlideDrawableImageViewTarget对象,我们使用的事asDrawable

public > Y into(@NonNull Y target) {
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    Request previous = target.getRequest();

    if (previous != null) {
      requestManager.clear(target);
    }

    requestOptions.lock();
    Request request = buildRequest(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }

再次检查是否是在主线程,以及view是否为空,并且通过isModelSet标记判断load
和into的先后顺序,我们关注核心代码,buildRequest构建了request对象,Request是用来发出加载图片请求的,它是Glide中非常关键的一个组件。我们先来看buildRequest()方法是如何构建Request对象的:

 private Request buildRequest(Target target) {
    return buildRequestRecursive(target, null, transitionOptions, requestOptions.getPriority(),
        requestOptions.getOverrideWidth(), requestOptions.getOverrideHeight());
  }

内部又调用了

 private Request buildRequestRecursive(Target target,
      @Nullable ThumbnailRequestCoordinator parentCoordinator,
      TransitionOptions transitionOptions,
      Priority priority, int overrideWidth, int overrideHeight) {
    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 thumbTransitionOptions =
          thumbnailBuilder.transitionOptions;
      if (DEFAULT_ANIMATION_OPTIONS.equals(thumbTransitionOptions)) {
        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, requestOptions, coordinator,
          transitionOptions, priority, overrideWidth, overrideHeight);
      isThumbnailBuilt = true;
      // Recursively generate thumbnail requests.
      Request thumbRequest = thumbnailBuilder.buildRequestRecursive(target, coordinator,
          thumbTransitionOptions, thumbPriority, thumbOverrideWidth, thumbOverrideHeight);
      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, requestOptions, coordinator, transitionOptions,
          priority, overrideWidth, overrideHeight);
      RequestOptions thumbnailOptions = requestOptions.clone()
          .sizeMultiplier(thumbSizeMultiplier);

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

      coordinator.setRequests(fullRequest, thumbnailRequest);
      return coordinator;
    } else {
      // Base case: no thumbnail.
      return obtainRequest(target, requestOptions, parentCoordinator, transitionOptions, priority,
          overrideWidth, overrideHeight);
    }
  }

大篇幅写的是如何处理缩略图的,我们关心这个方法obtainRequest

private Request obtainRequest(Target target,
      RequestOptions requestOptions, RequestCoordinator requestCoordinator,
      TransitionOptions transitionOptions, Priority priority,
      int overrideWidth, int overrideHeight) {
    requestOptions.lock();

    return SingleRequest.obtain(
        context,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        requestListener,
        requestCoordinator,
        context.getEngine(),
        transitionOptions.getTransitionFactory());
  }

在这里调用了SingleRequest的obtain方法,这么多参数,是不是把之前所有用到的api都添加到这个request中去了

 public static  SingleRequest obtain(
      GlideContext glideContext,
      Object model,
      Class transcodeClass,
      RequestOptions requestOptions,
      int overrideWidth,
      int overrideHeight,
      Priority priority,
      Target target,
      RequestListener requestListener,
      RequestCoordinator requestCoordinator,
      Engine engine,
      TransitionFactory animationFactory) {
    @SuppressWarnings("unchecked") SingleRequest request =
        (SingleRequest) POOL.acquire();
    if (request == null) {
      request = new SingleRequest<>();
    }
    request.init(
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        requestListener,
        requestCoordinator,
        engine,
        animationFactory);
    return request;
  }
private void init(
      GlideContext glideContext,
      Object model,
      Class transcodeClass,
      RequestOptions requestOptions,
      int overrideWidth,
      int overrideHeight,
      Priority priority,
      Target target,
      RequestListener requestListener,
      RequestCoordinator requestCoordinator,
      Engine engine,
      TransitionFactory animationFactory) {
    this.glideContext = glideContext;
    this.model = model;
    this.transcodeClass = transcodeClass;
    this.requestOptions = requestOptions;
    this.overrideWidth = overrideWidth;
    this.overrideHeight = overrideHeight;
    this.priority = priority;
    this.target = target;
    this.requestListener = requestListener;
    this.requestCoordinator = requestCoordinator;
    this.engine = engine;
    this.animationFactory = animationFactory;
    status = Status.PENDING;
  }

new 了一个SingleRequest对象,这个类是Request的实现类,下边的init实际上是对这些参数赋值,至此解决了创建request的问题,那么是怎么执行的呢
回到最还是into方法

Request request = buildRequest(target);
target.setRequest(request);
requestManager.track(target, request);

看看track方法

void track(Target target, Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }

这里涉及到TargetTracker这个类,是对目标view的生命周期进行跟踪管理的辅助类
接下来看runRequest这个方法

 public void runRequest(Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      pendingRequests.add(request);
    }
  }

这个RequestTracker类是对request进行队列管理的类,当请求不是暂停时请求开始,先不考虑暂停又开始的情况,由于上面分析了SingleRequest是Request的实现类,那么就去那看

public void begin() {
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    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;
    }

    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      target.getSize(this);
    }

    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      target.onLoadStarted(getPlaceholderDrawable());
    }
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
  }

当model==null时也就是load中传入的为空时我们看这个方法 onLoadFailed

private void onLoadFailed(GlideException e, int maxLogLevel) {
    stateVerifier.throwIfRecycled();
    int logLevel = glideContext.getLogLevel();
    if (logLevel <= maxLogLevel) {
      Log.w(GLIDE_TAG, "Load failed for " + model + " with size [" + width + "x" + height + "]", e);
      if (logLevel <= Log.INFO) {
        e.logRootCauses(GLIDE_TAG);
      }
    }

    loadStatus = null;
    status = Status.FAILED;
    //TODO: what if this is a thumbnail request?
    if (requestListener == null
        || !requestListener.onLoadFailed(e, model, target, isFirstReadyResource())) {
      setErrorPlaceholder();
    }
  }

执行了setErrorPlaceholder方法

private void setErrorPlaceholder() {
    if (!canNotifyStatusChanged()) {
      return;
    }

    Drawable error = null;
    if (model == null) {
      error = getFallbackDrawable();
    }
    // Either the model isn't null, or there was no fallback drawable set.
    if (error == null) {
      error = getErrorDrawable();
    }
    // The model isn't null, no fallback drawable was set or no error drawable was set.
    if (error == null) {
      error = getPlaceholderDrawable();
    }
    target.onLoadFailed(error);
  }

下面看一下getFallbackDrawable方法,是干什么的

 private Drawable getFallbackDrawable() {
    if (fallbackDrawable == null) {
      fallbackDrawable = requestOptions.getFallbackDrawable();
      if (fallbackDrawable == null && requestOptions.getFallbackId() > 0) {
        fallbackDrawable = loadDrawable(requestOptions.getFallbackId());
      }
    }
    return fallbackDrawable;
  }

public final Drawable getFallbackDrawable() {
    return fallbackDrawable;
  }

  /**
   * Sets an {@link Drawable} to display if the model provided to
   * {@link com.bumptech.glide.RequestBuilder#load(Object)} is {@code null}.
   *
   * 

If a fallback is not set, null models will cause the error drawable to be displayed. If the * error drawable is not set, the placeholder will be displayed. * * @see #placeholder(Drawable) * @see #placeholder(int) * * @param drawable The drawable to display as a placeholder. * @return This request builder. */ public RequestOptions fallback(Drawable drawable) { if (isAutoCloneEnabled) { return clone().fallback(drawable); } this.fallbackDrawable = drawable; fields |= FALLBACK; return selfOrThrowIfLocked(); }

这里写的很明白了,当load的参数为空的时展示一个占位图片,如果这个图片没有设置,就设置一个错误图片,如果错误图片都没设置的话只能设置一个loading图
下面看看target.onLoadFailed(error);这个方法干了什么:

/**
 * A lifecycle callback that is called when a load fails.
 *
 * 

Note - This may be called before {@link #onLoadStarted(android.graphics.drawable.Drawable) * } if the model object is null. * *

You must ensure that any current Drawable received in {@link #onResourceReady(Object, * Transition)} is no longer displayed before redrawing the container (usually a View) or * changing its visibility. * * @param errorDrawable The error drawable to optionally show, or null. */ void onLoadFailed(@Nullable Drawable errorDrawable);

这是个接口,看看具体实现

/**
   * Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
   * android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
   *
   * @param errorDrawable {@inheritDoc}
   */
  @Override
  public void onLoadFailed(@Nullable Drawable errorDrawable) {
    super.onLoadFailed(errorDrawable);
    setResourceInternal(null);
    setDrawable(errorDrawable);
  }

 @Override
  public void setDrawable(Drawable drawable) {
    view.setImageDrawable(drawable);
  }

这里可以看到,因为出现了 异常无法正常过的加载图片,具体的为view设置了图片,至于是什么图片则是给的什么接什么,让我们回到begin方法();
target.onLoadStarted()图片请求开始之前,会先使用这张占位图代替最终的图片显示,这也就是placeholder和error的底层实现原理
我们看看这个方法里边是什么

 /**
   * Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
   * android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
   *
   * @param placeholder {@inheritDoc}
   */
  @Override
  public void onLoadStarted(@Nullable Drawable placeholder) {
    super.onLoadStarted(placeholder);
    setResourceInternal(null);
    setDrawable(placeholder);
  }
  /**
   * Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
   * android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
   *
   * @param drawable {@inheritDoc}
   */
  @Override
  public void setDrawable(Drawable drawable) {
    view.setImageDrawable(drawable);
  }

知道了占位图的实现,那么 图片加载是从哪开始的呢,在begin方法里

if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      target.getSize(this);
    }

判断了下你是否指定了一个固定的宽高,不管你是否设置了宽高都会走这个方法

/**
   * A callback method that should never be invoked directly.
   */
  @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.getOptions(),
        requestOptions.isMemoryCacheable(),
        requestOptions.getUseUnlimitedSourceGeneratorsPool(),
        requestOptions.getOnlyRetrieveFromCache(),
        this);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
  }

从这开始涉及engine我们先看这个类是干嘛的


/**
 * Responsible for starting loads and managing active and cached resources.
 * 负责启动加载和管理活动和缓存资源。
 */
public class Engine implements EngineJobListener,
    MemoryCache.ResourceRemovedListener,
    EngineResource.ResourceListener {


/**
   * Starts a load for the given arguments. Must be called on the main thread.
   *
   * 

The flow for any request is as follows:

  • Check the memory cache and provide the * cached resource if present
  • Check the current put of actively used resources and return * the active resource if present
  • Check the current put of in progress loads and add the * cb to the in progress load if present
  • Start a new load

* *

Active resources are those that have been provided to at least one request and have not yet * been released. Once all consumers of a resource have released that resource, the resource then * goes to cache. If the resource is ever returned to a new consumer from cache, it is re-added to * the active resources. If the resource is evicted from the cache, its resources are recycled and * re-used if possible and the resource is discarded. There is no strict requirement that * consumers release their resources so active resources are held weakly.

* * @param width The target width in pixels of the desired resource. * @param height The target height in pixels of the desired resource. * @param cb The callback that will be called when the load completes. */ public LoadStatus load( GlideContext glideContext, Object model, Key signature, int width, int height, Class resourceClass, Class transcodeClass, Priority priority, DiskCacheStrategy diskCacheStrategy, Map, Transformation> transformations, boolean isTransformationRequired, Options options, boolean isMemoryCacheable, boolean useUnlimitedSourceExecutorPool, boolean onlyRetrieveFromCache, ResourceCallback cb) { Util.assertMainThread(); long startTime = LogTime.getLogTime(); //EngineKey 的介绍是An in memory only cache key used to multiplex loads. //内存中只缓存用于复用的键。所以这个key记录了一次加载的各种信息 EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options); 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; } 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的重复创建,EngineJob代表从硬盘缓存或者网络上加载图片并进行decode的整个过程。 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); } EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable, useUnlimitedSourceExecutorPool); DecodeJob decodeJob = decodeJobFactory.build( glideContext, model, key, signature, width, height, resourceClass, transcodeClass, priority, diskCacheStrategy, transformations, isTransformationRequired, 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的缓存机制
EngineKey 这个类是用产生一个用于进行缓存的Key,决定key的因素特别多,这个类通过重写了equals()和hashCode()方法,保证只有传入EngineKey的所有参数都相同的情况下才认为是同一个EngineKey对象

接下来看loadFromCache方法

private EngineResource loadFromCache(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
      return null;
    }

    EngineResource cached = getEngineResourceFromCache(key);
    if (cached != null) {
      cached.acquire();
      activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
    }
    return cached;
  }  

 private EngineResource getEngineResourceFromCache(Key key) {
    Resource cached = cache.remove(key);

    final EngineResource result;
    if (cached == null) {
      result = null;
    } else if (cached instanceof EngineResource) {
      // Save an object allocation if we've cached an EngineResource (the typical case).
      result = (EngineResource) cached;
    } else {
      result = new EngineResource<>(cached, true /*isMemoryCacheable*/);
    }
    return result;
  }


 private EngineResource loadFromActiveResources(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
      return null;
    }

    EngineResource active = null;
    WeakReference> activeRef = activeResources.get(key);
    if (activeRef != null) {
      active = activeRef.get();
      if (active != null) {
        active.acquire();
      } else {
        activeResources.remove(key);
      }
    }

    return active;
  }

为什么要判断isMemoryCacheable 呢是因为Glide自动帮我们开启了缓存如果想关闭这功能只需要在skipMemoryCache()方法传入true,那么在这里就是false,表示内存被禁用,接着调用了getEngineResourceFromCache()方法来获取缓存。在这个方法中,会使用缓存Key来从cache当中取值,而这里的cache对象就是在构建Glide对象时创建的LruResourceCache,那么说明这里其实使用的就是LruCache算法了,当我们从LruResourceCache中获取到缓存图片之后会将它从缓存中移除,然后在将这个缓存图片存储到activeResources当中。activeResources就是一个弱引用的HashMap,用来缓存正在使用中的图片,我们可以看到,loadFromActiveResources()方法就是从activeResources这个HashMap当中取值的。使用activeResources来缓存正在使用中的图片,可以保护这些图片不会被LruCache算法回收掉,如果有的话就直接在这获取,没有的话就开启线程去加载图片,接下来又进行了内存缓存的判断这里避免了EngineJob的重复创建,EngineJob代表从硬盘缓存或者网络上加载图片并进行decode的整个过程。

那么怎么开启的线程又是如何加载的呢:

EngineJob的职责是调度DecodeJob,添加,移除资源回调,并notify回调。DecodeJob负责从缓存资源或者原始数据中读取资源,Glide中的脏累活基本都是这个DecodeJob干的

先从engineJob.start去看

 public void start(DecodeJob decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }

利用线程池执行decodeJob,那么decodeJob又有什么猫腻
decodeJob中实现了Runnable看一下run方法

@Override
  public void run() {
    // This should be much more fine grained, but since Java's thread pool implementation silently
    // swallows all otherwise fatal exceptions, this will at least make it obvious to developers
    // that something is failing.
    TraceCompat.beginSection("DecodeJob#run");
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();
    } catch (RuntimeException e) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "DecodeJob threw unexpectedly"
            + ", isCancelled: " + isCancelled
            + ", stage: " + stage, e);
      }
      // When we're encoding we've already notified our callback and it isn't safe to do so again.
      if (stage != Stage.ENCODE) {
        notifyFailed();
      }
      if (!isCancelled) {
        throw e;
      }
    } finally {
      if (currentFetcher != null) {
        currentFetcher.cleanup();
      }
      TraceCompat.endSection();
    }
  }

貌似所有的逻辑处理都在runWrapped这个方法中

 private void runWrapped() {
     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);
    }
  }

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);
    }
  }

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;
      }
    }
    // We've run out of stages and generators, give up.
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
      notifyFailed();
    }

    // Otherwise a generator started a new load and we expect to be called back in
    // onDataFetcherReady.
  }

因为runReason的默认值是INITIALIZE,首先调用getNextStage方法获取到stage值,然后执行getNextGenerator根据stage不同的值获取相应的generator
一共有几种generators
ResourceCacheGenerator:从处理过的缓存加载数据
DataCacheGenerator:从原始缓存加载数据
SourceGenerator:从数据源请求数据

最后执行runGeneratores,currentGenerator.startNext()
点进去看到时候发现有3个
分别是:
DataCacheGenerator
ResourceCacheGenerator
SourceGenerator
这里主要看一下SourceGenerator的方法

 @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }

    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    sourceCacheGenerator = null;

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

接下来我们看loadData方法

/**
 * A DataFetcher that retrieves an {@link java.io.InputStream} for a Url.
 */
public class HttpUrlFetcher implements DataFetcher {
  @Override
  public void loadData(Priority priority, DataCallback callback) {
    long startTime = LogTime.getLogTime();
    final InputStream result;
    try {
      result = loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/,
          glideUrl.getHeaders());
    } catch (IOException e) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "Failed to load data for url", e);
      }
      callback.onLoadFailed(e);
      return;
    }
  if (Log.isLoggable(TAG, Log.VERBOSE)) {
      Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime)
          + " ms and loaded " + result);
    }
    callback.onDataReady(result);
}

 private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
      Map 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 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();
    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);
      return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
    } else if (statusCode == -1) {
      throw new HttpException(statusCode);
    } else {
      throw new HttpException(urlConnection.getResponseMessage(), statusCode);
    }
  }
)
private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
      throws IOException {
    if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
      int contentLength = urlConnection.getContentLength();
      stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
    } else {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "Got non empty content encoding: " + urlConnection.getContentEncoding());
      }
      stream = urlConnection.getInputStream();
    }
    return stream;
  }

到这我们是找到了网络通讯的代码了,通过网络下载获取到inputStream,然后把流给callback.onDataReady(result);
我们再看代码:SourceGenerator

 @Override
  public void onDataReady(Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      dataToCache = data;
      // We might be being called back on someone else's thread. Before doing anything, we should
      // reschedule to get back onto Glide's thread.
      cb.reschedule();
    } else {
      cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
          loadData.fetcher.getDataSource(), originalKey);
    }
  }

最后回调到decodejob的方法

@Override
  public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher fetcher,
      DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;
    this.currentData = data;
    this.currentFetcher = fetcher;
    this.currentDataSource = dataSource;
    this.currentAttemptingKey = attemptedKey;
    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
    } else {
      TraceCompat.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        decodeFromRetrievedData();
      } finally {
        TraceCompat.endSection();
      }
    }
  }

private void decodeFromRetrievedData() {
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logWithTimeAndKey("Retrieved data", startFetchTime,
          "data: " + currentData
          + ", cache key: " + currentSourceKey
          + ", fetcher: " + currentFetcher);
    }
    Resource resource = null;
    try {
      //把数据流编码成resource类型
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      exceptions.add(e);
    }
    if (resource != null) {
      //将resource返回
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }

private void notifyEncodeAndRelease(Resource resource, DataSource dataSource) {
    if (resource instanceof Initializable) {
      ((Initializable) resource).initialize();
    }
    Resource result = resource;
    LockedResource lockedResource = null;
    if (deferredEncodeManager.hasResourceToEncode()) {
      lockedResource = LockedResource.obtain(resource);
      result = lockedResource;
    }

    notifyComplete(result, dataSource);

    stage = Stage.ENCODE;
    try {
      if (deferredEncodeManager.hasResourceToEncode()) {
        deferredEncodeManager.encode(diskCacheProvider, options);
      }
    } finally {
      if (lockedResource != null) {
        lockedResource.unlock();
      }
      onEncodeComplete();
    }
  }


private void notifyComplete(Resource resource, DataSource dataSource) {
    setNotifiedOrThrow();
    callback.onResourceReady(resource, dataSource);
  }

最终把数据回调到onResourceReady

 @Override
  public void onResourceReady(Resource resource, DataSource dataSource) {
    this.resource = resource;
    this.dataSource = dataSource;
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
  }

之后发送了一条消息

private static class MainThreadCallback implements Handler.Callback {

    @Synthetic
    MainThreadCallback() { }

    @Override
    public boolean handleMessage(Message message) {
      EngineJob job = (EngineJob) message.obj;
      switch (message.what) {
        case MSG_COMPLETE:
          job.handleResultOnMainThread();
          break;
        case MSG_EXCEPTION:
          job.handleExceptionOnMainThread();
          break;
        case MSG_CANCELLED:
          job.handleCancelledOnMainThread();
          break;
        default:
          throw new IllegalStateException("Unrecognized message: " + message.what);
      }
      return true;
    }
  }

@Synthetic
  void handleResultOnMainThread() {
    stateVerifier.throwIfRecycled();
    if (isCancelled) {
      resource.recycle();
      release(false /*isRemovedFromQueue*/);
      return;
    } else if (cbs.isEmpty()) {
      throw new IllegalStateException("Received a resource without any callbacks to notify");
    } else if (hasResource) {
      throw new IllegalStateException("Already have resource");
    }
    engineResource = engineResourceFactory.build(resource, isCacheable);
    hasResource = true;

    // Hold on to resource for duration of request so we don't recycle it in the middle of
    // notifying if it synchronously released by one of the callbacks.
    engineResource.acquire();
    listener.onEngineJobComplete(key, engineResource);

    for (ResourceCallback cb : cbs) {
      if (!isInIgnoredCallbacks(cb)) {
        engineResource.acquire();
        cb.onResourceReady(engineResource, dataSource);
      }
    }
    // Our request is complete, so we can release the resource.
    engineResource.release();

    release(false /*isRemovedFromQueue*/);
  }

之后回调到SingleRequest

 @SuppressWarnings("unchecked")
  @Override
  public void onResourceReady(Resource resource, DataSource dataSource) {
    stateVerifier.throwIfRecycled();
    loadStatus = null;
    if (resource == null) {
      GlideException exception = new GlideException("Expected to receive a Resource with an "
          + "object of " + transcodeClass + " inside, but instead got null.");
      onLoadFailed(exception);
      return;
    }

    Object received = resource.get();
    if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
      releaseResource(resource);
      GlideException exception = new GlideException("Expected to receive an object of "
          + transcodeClass + " but instead" + " got "
          + (received != null ? received.getClass() : "") + "{" + received + "} inside" + " "
          + "Resource{" + resource + "}."
          + (received != null ? "" : " " + "To indicate failure return a null Resource "
          + "object, rather than a Resource object containing null data."));
      onLoadFailed(exception);
      return;
    }

    if (!canSetResource()) {
      releaseResource(resource);
      // We can't put the status to complete before asking canSetResource().
      status = Status.COMPLETE;
      return;
    }

    onResourceReady((Resource) resource, (R) received, dataSource);
  }

 private void onResourceReady(Resource resource, R result, DataSource dataSource) {
    // We must call isFirstReadyResource before setting status.
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;

    if (glideContext.getLogLevel() <= Log.DEBUG) {
      Log.d(GLIDE_TAG, "Finished loading " + result.getClass().getSimpleName() + " from "
          + dataSource + " for " + model + " with size [" + width + "x" + height + "] in "
          + LogTime.getElapsedMillis(startTime) + " ms");
    }

    if (requestListener == null
        || !requestListener.onResourceReady(result, model, target, dataSource, isFirstResource)) {
      Transition animation =
          animationFactory.build(dataSource, isFirstResource);
      target.onResourceReady(result, animation);
    }

    notifyLoadSuccess();
  }

最后我们看 target.onResourceReady(result, animation);这个方法
点进去一看

public abstract class ImageViewTarget extends ViewTarget
    implements Transition.ViewAdapter {
    @Override
  public void onResourceReady(Z resource, @Nullable Transition transition) {
    if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }
  }
}
 private void setResourceInternal(@Nullable Z resource) {
    maybeUpdateAnimatable(resource);
    setResource(resource);
  }
protected abstract void setResource(@Nullable Z resource);

至此就能把图片显示出来了,至于如何编码解码的并没有深入探讨分析,整体的过了一遍流程
总体来说跟3.7.0流程上还是有很大的区别的,至于没弄的细节有时间再弄。

你可能感兴趣的:(Gilde的源码学习)