Glide加载流程源码分析

前言

Glide是Android开发中,非常热门的一款图片加载框架,本篇来分析一下Glide的源码。

简单使用

Glide加载一个Http的Url图片,总共分3步,with(),load(),into(),源码分析也是从这3个API口子开始进行。

  • with(),通过context获取Glide实例,并且创建RequestManager,并且绑定context生命周期,例如context为Activity时,在onStop中暂停请求,onStart中恢复请求。
  • load(),通过一个url,获取RequestBuilder实例,并且把url保存起来。
  • into(),开始加载url,并把获取到的图片加载到传入的ImageView中。
Glide.with(context).load(url).into(imageView);

源码分析

Glide.with(context)

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

@NonNull
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).");
    //Glide.get(context),或者Glide单实例
    return Glide.get(context).getRequestManagerRetriever();
    }

    @NonNull
    public static Glide get(@NonNull Context context) {
    //双重double check实现单例
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          //构造Glide实例
          checkAndInitializeGlide(context);
        }
      }
    }

    return glide;
}
  • Glide.with(context),通过Context,获取Glide单实例,再获取RequestManagerRetriever对象
  • RequestManagerRetriever.get(context),获取RequestManager实例

Glide单例

Glide单例使用Double Check,双重检查来实现单例,最终会调用到build()方法,进行构建Glide实例,并初始化一些系列对象,例如GlideModuleRequestManagerRetrieverEngine

@NonNull
public static Glide get(@NonNull Context context) {
    //双重double check实现单例
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          //构造Glide实例
          checkAndInitializeGlide(context);
        }
      }
    }
    
    return glide;
}

private static void checkAndInitializeGlide(@NonNull Context context) {
    // In the thread running initGlide(), one or more classes may call Glide.get(context).
    // Without this check, those calls could trigger infinite recursion.
    if (isInitializing) {
      throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
          + " use the provided Glide instance instead");
    }
    isInitializing = true;
    //构造Glide实例
    initializeGlide(context);
    isInitializing = false;
}

/**
* 构造Glide实例
*/
private static void initializeGlide(@NonNull Context context) {
    initializeGlide(context, new GlideBuilder());
}

/**
* 构造Glide实例
*
* @param builder Glide配置
*/
@SuppressWarnings("deprecation")
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
    Context applicationContext = context.getApplicationContext();
    //反射创建 com.bumptech.glide.GeneratedAppGlideModuleImpl,如果能找到,就说明自定义了GlideModule
    GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
    List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
    if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
      //找不到,但开启了isManifestParsingEnabled,就读取AndroidManifest.xml上配置的GlideModule
      manifestModules = new ManifestParser(applicationContext).parse();
    }
    //根据配置的GlideModule过滤名单,剔除名单上配置的GlideModule
    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;
        }
        if (Log.isLoggable(TAG, Log.DEBUG)) {
          Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
        }
        iterator.remove();
      }
    }
    
    if (Log.isLoggable(TAG, Log.DEBUG)) {
      for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
        Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
      }
    }
    
    //获取RequestManager工厂,用于在with()方法中,创建RequestManager
    RequestManagerRetriever.RequestManagerFactory factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManagerFactory() : null;
    builder.setRequestManagerFactory(factory);
    //遍历调用AndroidManifest.xml中配置的GlideModule上配置的applyOptions()方法
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      module.applyOptions(applicationContext, builder);
    }
    //遍历调用注解配置的GlideModule上配置的applyOptions()方法
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.applyOptions(applicationContext, builder);
    }
    //构建Glide实例
    Glide glide = builder.build(applicationContext);
    //调用AndroidManifest.xml中配置的GlideModule中的registerComponents()方法
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      module.registerComponents(applicationContext, glide, glide.registry);
    }
    //调用注解配置的GlideModule中的registerComponents()方法
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    }
    //Glide实现了ComponentCallbacks接口,用于被通知onConfigurationChanged()配置改变和onLowMemory()低内存通知
    applicationContext.registerComponentCallbacks(glide);
    //单例变量赋值
    Glide.glide = glide;
}

/**
* Glide的构造
*/
@NonNull
Glide build(@NonNull Context context) {
    //源执行器,允许在其线程上进行网络操作,获取资源
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }
    
    //磁盘缓存执行器,不允许对其线程进行网络操作
    if (diskCacheExecutor == null) {
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }
    
    //动画执行器,不允许在其线程上进行网络操作
    if (animationExecutor == null) {
      animationExecutor = GlideExecutor.newAnimationExecutor();
    }
    
    //根据设备的参数计算需要设置的缓存大小
    if (memorySizeCalculator == null) {
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }
    
    //网络连接监听工厂
    if (connectivityMonitorFactory == null) {
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }
    
    //Bitmap缓存池,用于图片的缓存,使用LRUCache
    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) {
        //LRUCache缓存
        bitmapPool = new LruBitmapPool(size);
      } else {
        //不使用缓存
        bitmapPool = new BitmapPoolAdapter();
      }
    }
    
    //一个固定大小的数组池,使用LRU策略,让池保持在最大字节下
    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }
    
    //图片内存缓存
    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }
    
    //磁盘缓存
    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }
    
    //创建Engine,用于发起Request网络请求,读取磁盘图片
    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              GlideExecutor.newAnimationExecutor(),
              isActiveResourceRetentionAllowed);
    }
    
    //创建RequestManagerRetriever对象,getRetriever()方法返回该实例
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);
    
    //构造Glide
    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions);
}

RequestManager 请求管理器

RequestManager.get(context),通过Context,获取RequestManager实例,判断Context的类型,判空,当前为主线程,并且不是Application,判断是FragmentActivity、还是Activity、如果是ContextWrapper,则获取getBaseContext()递归再获取一遍。

@NonNull
public RequestManager get(@NonNull Context context) {
    if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
      //找宿主Activity来创建RequestManager
      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());
      }
    }
    //通过ApplicationContext,获取RequestManager
    return getApplicationManager(context);
}

以Context为FragmentActivity为例,看看做了些什么。

@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
    //如果不是主线程调用,使用ApplicationContext
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      //主线程,检查Activity是否销毁
      assertNotDestroyed(activity);
      //获取Fragment管理器
      FragmentManager fm = activity.getSupportFragmentManager();
      //通过插入SupportFragment来获取RequestManager
      //RequestManager被Glide用于开始、停止、管理Glide的请求
      return supportFragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
}

/**
* 通过插入SupportFragment来获取RequestManager
*/
@NonNull
private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    //获取Fragment实例
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    //从Fragment上,获取RequestManager实例
    RequestManager requestManager = current.getRequestManager();
    //Fragment上没有,则通过工厂进行创建
    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);
      //让Fragment持有RequestManager实例,下次就不需要再创建了
      current.setRequestManager(requestManager);
    }
    return requestManager;
}

/**
* 添加插入一个空的Fragment到Activity或Fragment上
*/
@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(
  @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    //通过Tag查找
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    //没有添加过
    if (current == null) {
      //从缓存map中查找,找到则直接返回
      current = pendingSupportRequestManagerFragments.get(fm);
      //也找不到,则创建一个
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        //如果当前页面已经是可见的,那么马上调用lifecycle的onStart()
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        //加进缓存map,由于快速滚动会频繁触发,并且Fragment的事务是异步的,如果没有这个缓存map,可能会插入多个Fragment
        pendingSupportRequestManagerFragments.put(fm, current);
        //添加Fragment
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        //发消息到主线程,由于Fragment的事务也是通过Handler来进行异步的
        //所以这个消息如果被执行,那Fragment的事务肯定已经处理完了,那么就可以从map上移除Fragment实例了
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
}
  • 获取FragmentActivity的FragmentManager,通过Tag查找SupportRequestManagerFragment实例,如果没有获取到,去pendingSupportRequestManagerFragments这个Map中获取
  • 如果能获取到,则取出Fragment绑定的RequestManager实例
  • 如果还是没有获取到,则创建这个Fragment实例,并把RequestManager通过setRequestManager(),把它们绑定起来
  • SupportRequestManagerFragment,其实是一个没有布局的Fragment,通过它来获取Activity的生命周期回调

RequestManager.load(url)

@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
    //asDrawable(),创建一个RequestBuilder,并且指定它的泛型为Drawable类型
    //调用RequestBuilder的load()方法,传入url
    return asDrawable().load(string);
}

@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
}

@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
  @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
}

@NonNull
@CheckResult
@Override
public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
    return loadGeneric(resourceId).apply(signatureOf(ApplicationVersionSignature.obtain(context)));
}

@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    //保存了加载的资源
    this.model = model;
    //设置标志位,加载的时候会用到,如果没有设置为true,则直接执行错误回调
    isModelSet = true;
    return this;
}
  • load()方法做的事情非常少,首先创建了一个RequestBuilder实例,并且指定它的泛型为Drawable,然后把传入的url,保存起来,并且设置了一个isModelSet标志位为true,就返回出去了

RequestBuilder.into(imageView)

@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull 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.
      //根据ImageView设置的ScaleType,添加对应的RequestOption
      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.
      }
    }
    //transcodeClass是前面load()保存的资源类型
    return into(
        //构建ViewTarget,例如 DrawableImageViewTarget
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions);
}

/**
* 根据要加载的资源的类型,构建ViewTarget
*/
@NonNull
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) {
    //加载成Bitmap,通过setImageBitmap(),设置给ImageView
    if (Bitmap.class.equals(clazz)) {
      return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      //加载成Drawable,通过setImageDrawable(),设置给ImageView
      //例如传入url,Glide.with(context).load(url).into(view),会通过asDrawable(),clazz就为Drawable.class
      return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }
}
  • 获取ImageView的ScaleType,就是缩放类型,如果有添加,则设置对应的类型到RequestOptions
  • 随后调用重载的into()方法
    • 调用buildImageViewTarget(),创建ViewTarget,并根据加载类型transcodeClass,创建BitmapImageViewTarget还是DrawableImageViewTarget,例如字符串Url,创建的类型为DrawableImageViewTarget
    • RequestListener,targetListener,请求监听,包含加载成功和加载失败2个回调,这里传的是null
    • RequestOptions,请求配置项

into(target, reqeuestListener, options)

private <Y extends Target<TranscodeType>> Y into(
  @NonNull Y target,
  @Nullable RequestListener<TranscodeType> targetListener,
  @NonNull RequestOptions options) {
    //必须主线程
    Util.assertMainThread();
    //非空判断
    Preconditions.checkNotNull(target);
    //在RequestBuilder的load()方法中,会设置该标志位为true
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
    
    options = options.autoClone();
    
    //创建请求,用于显示图片,可能来自内存缓存、磁盘缓存或网络中
    //返回的Request接口实现是SingleRequest
    Request request = buildRequest(target, targetListener, options);
    
    //拿出之前的请求做对比,如果能够复用,则复用之前的请求
    Request previous = target.getRequest();
    //2个请求的配置一致,那么可以考虑复用
    if (request.isEquivalentTo(previous)
            //设置了忽略缓存或previous还没有完成
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      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 un-tracking Targets, and obtaining View dimensions
        // that are done in the individual Request.
        //开始请求
        previous.begin();
      }
      return target;
    }
    
    //不能复用之前的请求previous,那么就清除掉target上保存的request
    requestManager.clear(target);
    //重新设置新的request,并且设置到ImageView的tag上
    target.setRequest(request);
    //开始请求
    requestManager.track(target, request);
    
    return target;
}
  • 通过buildRequest(),创建一个Request请求对象
  • 通过传入的Target对象,获取已存在的请求Reqeust对象
  • 判断是否可以复用已存在的请求
    • request和previous是否参数、请求类型都一致
    • 是否设置了跳过缓存,并且previous已完成
  • 如果不能复用,那么久构建新的Request对象,并通过RequestManager.track(target, request)开始请求

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;
    if (errorBuilder != null) {
      errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }
    
    //创建略缩图和原图的Request
    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions);
    
    if (errorRequestCoordinator == null) {
      return mainRequest;
    }
    
    int errorOverrideWidth = errorBuilder.requestOptions.getOverrideWidth();
    int errorOverrideHeight = errorBuilder.requestOptions.getOverrideHeight();
    if (Util.isValidDimensions(overrideWidth, overrideHeight)
        && !errorBuilder.requestOptions.isValidOverride()) {
      errorOverrideWidth = requestOptions.getOverrideWidth();
      errorOverrideHeight = requestOptions.getOverrideHeight();
    }
    
    //错误时要显示的图片的Request
    Request errorRequest = errorBuilder.buildRequestRecursive(
        target,
        targetListener,
        errorRequestCoordinator,
        errorBuilder.transitionOptions,
        errorBuilder.requestOptions.getPriority(),
        errorOverrideWidth,
        errorOverrideHeight,
        errorBuilder.requestOptions);
    //把2个请求组合到ErrorRequestCoordinator
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
}
  • 判断errorBuilder是否为空,这个errorBuilder是通过RequestBuilder.error()进行设置的,如果不为空,则将生成一个协调器ErrorRequestCoordinator,用于和下面的mainRequesterrorRequest进行协调,默认没有设置
  • buildThumbnailRequestRecursive(),生成mainRequest
  • 如果errorRequestCoordinator为空,则直接返回mainRequest
  • 如果errorRequestCoordinator不为空,则创建一个errorRequest,组合mainRequesterrorRequest,返回errorRequestCoordinator

buildThumbnailRequestRecursive()

/**
* 创建略缩图和原图的Request
*/
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);
    }
}
  • 这个方法,用于创建略缩图和原图的Request,略缩图我们先不管,先看else逻辑obtainRequest()

obtainRequest()

/**
* 生成一个请求,会在池中复用,享元模式
*/
private Request obtainRequest(
  Target<TranscodeType> target,
  RequestListener<TranscodeType> targetListener,
  RequestOptions requestOptions,
  RequestCoordinator requestCoordinator,
  TransitionOptions<?, ? super TranscodeType> transitionOptions,
  Priority priority,
  int overrideWidth,
  int overrideHeight) {
    //返回Request接口的实现类SingleRequest
    return SingleRequest.obtain(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory());
}
  • 创建一个SingleRequest实例返回,这里将会回到into()逻辑,RequestManager.track(target, request),这里的Request其实就是SingleRequest

RequestManager.track(target,request)

void track(@NonNull Target<?> target, @NonNull Request request) {
    //管理所有请求的状态,在页面生命周期变化时,控制请求做相应的处理
    targetTracker.track(target);
    //发起请求
    requestTracker.runRequest(request);
}

//管理所有请求的状态,在页面生命周期变化时,控制请求做相应的处理
public final class TargetTracker implements LifecycleListener {
  private final Set<Target<?>> targets =
      Collections.newSetFromMap(new WeakHashMap<Target<?>, Boolean>());

  public void track(@NonNull Target<?> target) {
    targets.add(target);
  }

  public void untrack(@NonNull Target<?> target) {
    targets.remove(target);
  }

  @Override
  public void onStart() {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onStart();
    }
  }

  @Override
  public void onStop() {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onStop();
    }
  }

  @Override
  public void onDestroy() {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onDestroy();
    }
  }

  @NonNull
  public List<Target<?>> getAll() {
    return Util.getSnapshot(targets);
  }

  public void clear() {
    targets.clear();
  }
}

/**
* Starts tracking the given request.
* 开始请求
*/
public void runRequest(@NonNull Request request) {
    //添加请求到运行的队列中
    requests.add(request);
    //没有暂停,那么开始请求
    if (!isPaused) {
      request.begin();
    } else {
      //暂停了,先清理
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      //添加到等待运行的队列中
      pendingRequests.add(request);
    }
}
  • 首先,targetTracker.track(target);,把Target添加到TargetTracker.targets集合中,并在在页面生命周期变化时,控制请求做相应的处理
  • 接着,requestTracker.runRequest(request);,先把SingleRequest添加到RequestTracker.requests队列中,如果当前不是暂停状态状态,那么调用SingleRequest.begin(),如果是暂停状态,则先加入到pendingRequests等待运行的队列中

SingleRequest.begin()

@Override
public void begin() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    //如果model,就是传入的url等资源,为空,则回调加载失败
    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;
    }
    
    //已经是运行中,不允许再用这个对象发起请求
    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.
    
    //Glide对根据ImageView的宽高来进行缓存,所以需要获取ImageView的宽高,overrideWidth和overrideHeight默认为-1
    status = Status.WAITING_FOR_SIZE;
    //第一次请求,是还没有获取宽高的,所以会走else逻辑去获取宽高
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      //获取ImageView的宽高,target是前面buildImageViewTarget的时候,生成的DrawableImageViewTarget
      //getSize()方法在它的父类ViewTarget中,获取成功会回调当前SingleRequest的onSizeReady()方法
      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));
    }
}
  • 首先,判断model,也就是我们传入的url,是否为空,如果为空,则直接返回,并回调onLoadFailed()
  • 判断当前状态是否是RUNNING状态,如果是,则抛异常,保证一个Request只能同时执行一次
  • 如果是COMMPLETE状态,那么可以直接返回resource,回调onResourceReady,并把获取到的Drawable设置到ImageView上
  • 判断宽高是否有效,如有效,则调用onSizeReady(),开始加载,并设置状态为RUNNING
  • 如果状态为RUNNING,或者为WAITING_FOR_SIZE状态,则显示展位图

SingleRequest.onSizeReady(width, height)

/**
* A callback method that should never be invoked directly.
* 获取ImageView的宽高成功
*/
@Override
public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    if (IS_VERBOSE_LOGGABLE) {
      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 (IS_VERBOSE_LOGGABLE) {
      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);
    
    // This is a hack that's only useful for testing right now where loads complete synchronously
    // even though under any executor running on any thread but the main thread, the load would
    // have completed asynchronously.
    if (status != Status.RUNNING) {
      loadStatus = null;
    }
    if (IS_VERBOSE_LOGGABLE) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
}
  • 首先,把状态更改为RUNNING
  • 通过Engine.load(),加载图片

Engine.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 = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
        
    //生成缓存Key,通过这个key,在缓存中查找
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
        
    //先从活动缓存中找
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      //找到了,直接返回
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }
        
    //活动缓存中没有,则从内存缓存中招
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      //找到了,直接返回
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }
        
    //2个内存缓存都没有,那么从缓存中,获取一个加载它的EngineJob
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      current.addCallback(cb);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }
        
    //缓存中没有,创建一个EngineJob
    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);
        
    //创建解码任务的DecodeJob,用于处理图片
    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);
        
    //缓存EngineJob,下次可以直接在缓存中取
    jobs.put(key, engineJob);
        
    engineJob.addCallback(cb);
    //把DecodeJob交给EngineJob
    engineJob.start(decodeJob);
        
    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
}
  • 生成EngineKey,用于读取和写入缓存时使用
  • 从缓存中查找,先在ActivityResource活动缓存中查找,再去MemoryCache内存缓存中查找
  • 如果内存缓存没有命中,则开始新的任务
  • jobs.get(key),先从Job缓存Map中查找任务,如果有则直接返回,没有则创建EngineJob
  • EngineJob,用于开启任务,回调资源加载成功或失败
  • 创建DecodeJob,用于加载资源,操作缓存等,将DecodeJobEngineJob通过Callback的形式,绑定起来
  • 调用DecodeJob.start(decodeJob),执行任务
/**
* 开始任务
*
* @param decodeJob 图片解码DecodeJob
*/
public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    //如果能从磁盘缓存中加载,则使用diskCacheExecutor,否则根据情况判断使用哪个GlideExecutor
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    //把decodeJob交给GlideExecutor执行,会回调DecodeJob的run()方法
    executor.execute(decodeJob);
}
  • EngineJob.start(),其实就是通过线程池,调用DecodeJobrun()方法

DecodeJob.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.
    GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
    // Methods in the try statement can invalidate currentFetcher, so set a local variable here to
    // ensure that the fetcher is cleaned up either way.
    DataFetcher<?> localFetcher = currentFetcher;
    try {
      //如果已经取消,则回调失败
      if (isCancelled) {
        notifyFailed();
        return;
      }
      //运行的核心逻辑,runWrapped()
      runWrapped();
    } catch (Throwable t) {
      // Catch Throwable and not Exception to handle OOMs. Throwables are swallowed by our
      // usage of .submit() in GlideExecutor so we're not silently hiding crashes by doing this. We
      // are however ensuring that our callbacks are always notified when a load fails. Without this
      // notification, uncaught throwables never notify the corresponding callbacks, which can cause
      // loads to silently hang forever, a case that's especially bad for users using Futures on
      // background threads.
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "DecodeJob threw unexpectedly"
            + ", isCancelled: " + isCancelled
            + ", stage: " + stage, t);
      }
      // When we're encoding we've already notified our callback and it isn't safe to do so again.
      if (stage != Stage.ENCODE) {
        throwables.add(t);
        notifyFailed();
      }
      if (!isCancelled) {
        throw t;
      }
    } finally {
      // Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
      // close in all cases anyway.
      if (localFetcher != null) {
        localFetcher.cleanup();
      }
      GlideTrace.endSection();
    }
}
  • run()方法,如果任务已取消,则回调失败
  • 核心逻辑,runWrapped()方法

DecodeJob.runWrapped()

/**
* 运行的核心逻辑
*/
private void runWrapped() {
    switch (runReason) {
      //初始阶段
      case INITIALIZE:
        //获取下一个阶段的状态,返回 RESOURCE_CACHE
        stage = getNextStage(Stage.INITIALIZE);
        //根据下一个阶段的状态,判断出是哪一个Generator来执行,因为是RESOURCE_CACHE,那么这里返回的是ResourceCacheGenerator
        currentGenerator = getNextGenerator();
        //执行Generator
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        //尝试从磁盘缓存切到内存缓存
        runGenerators();
        break;
      case DECODE_DATA:
        //解码原数据,也就是去加载资源
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
}

private Stage getNextStage(Stage current) {
    switch (current) {
      //如果是初始阶段,那看配置的缓存策略,是否能从磁盘中获取资源缓存,就是解析好的缓存
      case INITIALIZE:
        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:
        // Skip loading from source if the user opted to only retrieve the resource from cache.
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
}

/**
* 获取下一个DataFetcherGenerator
*/
private DataFetcherGenerator getNextGenerator() {
    //主要看DataFetcherGenerator的startNext()方法
    switch (stage) {
      //ResourceCacheGenerator,寻找是否有经过转换、解码之后的磁盘文件缓存,这个缓存要比源文件缓存小
      case RESOURCE_CACHE:
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
        //DataCacheGenerator,寻找源文件磁盘缓存,这个是加载的源文件直接写入缓存
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
        //上面2个缓存Generator都没有命中,则通过SourceGenerator,那么Http请求获取资源,资源请求回来之后先写入磁盘缓存,再返回到Target
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
}

private enum RunReason {
    /** The first time we've been submitted. */
    //首次提交任务
    INITIALIZE,
    /**
     * We want to switch from the disk cache service to the source executor.
     * 尝试从磁盘缓存切到内存缓存
     */
    SWITCH_TO_SOURCE_SERVICE,
    /**
     * We retrieved some data on a thread we don't own and want to switch back to our thread to
     * process the data.
     * 解码原数据,也就是去加载资源
     */
    DECODE_DATA,
}
  • RunReason枚举类,有3个状态
    • INITIALIZE,首次提交任务
    • SWITCH_TO_SOURCE_SERVICE,尝试从磁盘缓存切到内存缓存
    • DECODE_DATA,解码原数据,也就是去加载资源

runWrapped()方法,runReason默认为INITIALIZE,所以我们先看getNextStage(Stage.INITIALIZE)

  • getNextStage(Stage.INITIALIZE),获取下一个阶段,默认缓存都是开的,所以下一个阶段为tage.RESOURCE_CACHE
  • 通过getNextGenerator(),获取DataFetcherGenerator,由于StageRESOURCE_CACHE,那么获取到的是ResourceCacheGenerator,它是从磁盘中获取是否有经过编解码,转码之后的缓存,这个缓存要比源文件缓存小
  • 最后,调用runGenerators()

DecodeJob.runGenerators()

/**
* 执行Generator
*/
private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled && currentGenerator != null
            //执行Generator的startNext,这里Generator是ResourceCacheGenerator
            //如果获取不到,则去DataCacheGenerator,从缓存中查找,也找不到则去SourceGenerator
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();
    
      //只有循环到为Stage.SOURCE,才会结束循环
      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.
}
  • 该方法,会进入一个while循环,并通过currentGenerator.startNext(),也就是ResourceCacheGenerator,去查找缓存,如果查找不到缓存,则通过SourceGenerator去执行
  • 直到stageStage.SOURCE,才会停止循环,并调用reschedule()

EngineJob.reschedule()

@Override
public void reschedule() {
    //首先将runReason置为SWITCH_TO_SOURCE_SERVICE,尝试从磁盘缓存切到内存缓存
    runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
    //callback就是EngineJob,所以回到EngineJob.reschedule()方法
    callback.reschedule(this);
}
  • 首先将runReason置为SWITCH_TO_SOURCE_SERVICE,尝试从磁盘缓存切到内存缓存
  • 调用callback.reschedule(this);,这个callback就是EngineJob,所以又回到EngineJob.reschedule()方法

EngineJob.reschedule()

@Override
public void reschedule(DecodeJob<?> job) {
    // Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself
    // up.
    getActiveSourceExecutor().execute(job);
}
  • 通过getActiveSourceExecutor()拿到sourceExecutor线程池,执行DecodeJob
  • 又会回到DecodeJob.run()方法,此时runReason已经为SWITCH_TO_SOURCE_SERVICE,并且stageSOURCE
  • DecodeJob.runGenerators()方法中,currentGenerator已经为DataSourceGenerator,它会查找是否有源文件缓存,有则直接返回,没有则通过SourceGenerator去加载资源

ResourceCacheGenerator.startNext()

@Override
public boolean startNext() {
    //获取缓存Key,会返回GlideUrl
    List<Key> sourceIds = helper.getCacheKeys();
    if (sourceIds.isEmpty()) {
      return false;
    }
    //获取3个可以到达的registeredResourceClasses,GifDrawable、Bitmap、BitmapDrawable
    List<Class<?>> resourceClasses = helper.getRegisteredResourceClasses();
    if (resourceClasses.isEmpty()) {
      if (File.class.equals(helper.getTranscodeClass())) {
        return false;
      }
      // TODO(b/73882030): This case gets triggered when it shouldn't. With this assertion it causes
      // all loads to fail. Without this assertion it causes loads to miss the disk cache
      // unnecessarily
      // throw new IllegalStateException(
      //    "Failed to find any load path from " + helper.getModelClass() + " to "
      //        + helper.getTranscodeClass());
    }
    while (modelLoaders == null || !hasNextModelLoader()) {
      resourceClassIndex++;
      if (resourceClassIndex >= resourceClasses.size()) {
        sourceIdIndex++;
        if (sourceIdIndex >= sourceIds.size()) {
          //如果是第一次请求,就会在这里返回
          return false;
        }
        resourceClassIndex = 0;
      }
    
      Key sourceId = sourceIds.get(sourceIdIndex);
      Class<?> resourceClass = resourceClasses.get(resourceClassIndex);
      Transformation<?> transformation = helper.getTransformation(resourceClass);
      // PMD.AvoidInstantiatingObjectsInLoops Each iteration is comparatively expensive anyway,
      // we only run until the first one succeeds, the loop runs for only a limited
      // number of iterations on the order of 10-20 in the worst case.
      currentKey =
          new ResourceCacheKey(// NOPMD AvoidInstantiatingObjectsInLoops
              helper.getArrayPool(),
              sourceId,
              helper.getSignature(),
              helper.getWidth(),
              helper.getHeight(),
              transformation,
              resourceClass,
              helper.getOptions());
      cacheFile = helper.getDiskCache().get(currentKey);
      if (cacheFile != null) {
        sourceKey = sourceId;
        modelLoaders = helper.getModelLoaders(cacheFile);
        modelLoaderIndex = 0;
      }
    }
    
    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
      loadData = modelLoader.buildLoadData(cacheFile,
          helper.getWidth(), helper.getHeight(), helper.getOptions());
      if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    
    return started;
}
  • 先从ResourceCacheGenerator中去寻找是否有经过转换、解码之后的磁盘文件缓存,这个缓存要比源文件缓存小

DataSourceGenerator.startNext()

@Override
public boolean startNext() {
    //如果能从缓存中获取文件,能找到就返回,否则进去到下一个Generator,下一个是SourceGenerator
    while (modelLoaders == null || !hasNextModelLoader()) {
      sourceIdIndex++;
      if (sourceIdIndex >= cacheKeys.size()) {
        return false;
      }
    
      Key sourceId = cacheKeys.get(sourceIdIndex);
      // PMD.AvoidInstantiatingObjectsInLoops The loop iterates a limited number of times
      // and the actions it performs are much more expensive than a single allocation.
      @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
      Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
      cacheFile = helper.getDiskCache().get(originalKey);
      if (cacheFile != null) {
        this.sourceKey = sourceId;
        modelLoaders = helper.getModelLoaders(cacheFile);
        modelLoaderIndex = 0;
      }
    }
    
    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
      loadData =
          modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
              helper.getOptions());
      if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
}
  • 再从DataSourceGenerator中寻找源文件磁盘缓存,这个是加载的源文件直接写入缓存;

SourceGenerator.startNext()

@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()) {
  //获取一个ModelLoader加载器
  loadData = helper.getLoadData().get(loadDataListIndex++);
  if (loadData != null
      && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
      || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
    started = true;
    //fetcher是HttpUrlFetcher,通过它来请求数据,同时设置回调callback为自身,回调到自身实现的onDataReady()
    loadData.fetcher.loadData(helper.getPriority(), this);
  }
}
return started;
}
  • 如果都没命中,那么就去Http请求资源,资源请求回来之后先写入磁盘缓存,再返回到Target。

HttpUrlFetcher.loadData()

//--------------------- HttpUrlFetcher ---------------------
@Override
public void loadData(@NonNull Priority priority,
  @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
      //通过loadDataWithRedirects(),请求回来的数据转换为InputStream,回调给callback
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      //回调onDataReady()
      callback.onDataReady(result);
    } catch (IOException e) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "Failed to load data for url", e);
      }
      callback.onLoadFailed(e);
    } finally {
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
      }
    }
}

/**
* 请求数据,通过HttpURLConnection
*/
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 (isHttpOk(statusCode)) {
      return getStreamForSuccessfulRequest(urlConnection);
    } else if (isHttpRedirect(statusCode)) {
      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 == INVALID_STATUS_CODE) {
      throw new HttpException(statusCode);
    } else {
      throw new HttpException(urlConnection.getResponseMessage(), statusCode);
    }
}

//--------------------- 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);
  }
}
  • HttpUrlFetcher,通过HttpURLConnection发起请求,并把数据转换为InputStream
  • 获取数据成功,回调callback.onDataReady,这callback是SourceGenerator,然后回调cb.onDataFetcherReady,这个cb是DecodeJob,所以回调到DecodeJob.onDataFetcherReady ()

DecodeJob.onDataFetcherReady()

@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 {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        //解析获取到的数据
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
}

/**
* 解析获取到的数据
*/
private void decodeFromRetrievedData() {
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logWithTimeAndKey("Retrieved data", startFetchTime,
          "data: " + currentData
              + ", cache key: " + currentSourceKey
              + ", fetcher: " + currentFetcher);
    }
    Resource<R> resource = null;
    try {
      //通过decodeFromData()获取Resource
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    //解析完成,通知下去
    if (resource != null) {
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
}

/**
* 通知调用层,数据已经准备好了
*/
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
    if (resource instanceof Initializable) {
      ((Initializable) resource).initialize();
    }
    
    Resource<R> result = resource;
    LockedResource<R> 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();
      }
    }
    // Call onEncodeComplete outside the finally block so that it's not called if the encode process
    // throws.
    //通知解码完成
    onEncodeComplete();
}

/**
* 通知调用层,数据已经准备好了
*/
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
    //这个Callback是EngineJob
    callback.onResourceReady(resource, dataSource);
}
  • 最后回调callback.onResourceReady(),其实就是EngineJob.onResourceReady()

EngineJob.onResourceReady()

@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    this.resource = resource;
    this.dataSource = dataSource;
    //在主线程回调中,通知上层Engine任务完成了
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}

private static class MainThreadCallback implements Handler.Callback {
    @Synthetic
    @SuppressWarnings("WeakerAccess")
    MainThreadCallback() { }
    
    @Override
    public boolean handleMessage(Message message) {
      EngineJob<?> job = (EngineJob<?>) message.obj;
      switch (message.what) {
        case MSG_COMPLETE:
          //通知Engine,任务完成了
          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();
    //回调Engine层,任务完成
    listener.onEngineJobComplete(this, key, engineResource);
    
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = cbs.size(); i < size; i++) {
      ResourceCallback cb = cbs.get(i);
      if (!isInIgnoredCallbacks(cb)) {
        engineResource.acquire();
        //回调给SingleRequest,通知资源获取到了
        cb.onResourceReady(engineResource, dataSource);
      }
    }
    // Our request is complete, so we can release the resource.
    engineResource.release();
    
    release(false /*isRemovedFromQueue*/);
}
  • 通过Handler,把加载结果回调给Engine
  • 并且回调SingleRequest.onResourceReady()

SingleRequest.onResourceReady()

@Override
public void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
    loadStatus = null;
    if (resource == null) {
      GlideException exception = new GlideException("Expected to receive a Resource<R> 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<R>) resource, (R) received, dataSource);
}

private void onResourceReady(Resource<R> 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");
    }
    
    isCallingCallbacks = true;
    try {
      boolean anyListenerHandledUpdatingTarget = false;
      if (requestListeners != null) {
        for (RequestListener<R> listener : requestListeners) {
          anyListenerHandledUpdatingTarget |=
              listener.onResourceReady(result, model, target, dataSource, isFirstResource);
        }
      }
      anyListenerHandledUpdatingTarget |=
          targetListener != null
              && targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
    
      if (!anyListenerHandledUpdatingTarget) {
        Transition<? super R> animation =
            animationFactory.build(dataSource, isFirstResource);
        //通知ImageViewTarget,资源加载完成
        target.onResourceReady(result, animation);
      }
    } finally {
      isCallingCallbacks = false;
    }
    
    notifyLoadSuccess();
}
  • 回调给ImageViewTarget.onResourceReady(),告知资源加载完成

ImageViewTarget.onResourceReady()

@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
    //资源加载好了,那么设置资源
    if (transition == null || !transition.transition(resource, this)) {
      //设置资源
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }
}

/**
* 设置资源
*/
private void setResourceInternal(@Nullable Z resource) {
    // Order matters here. Set the resource first to make sure that the Drawable has a valid and
    // non-null Callback before starting it.
    //setResource()是一个抽象方法,由子类去实现,例如DrawableImageViewTarget
    setResource(resource);
    maybeUpdateAnimatable(resource);
}

protected abstract void setResource(@Nullable Z resource);
  • 回调子类的setResource()方法,该方法被BitmapImageViewTargetDrawableImageViewTarget实现,例如我们传入字符串的url,ViewTarget就为DrawableImageViewTarget

DrawableImageViewTarget.setResource()

@Override
protected void setResource(@Nullable Drawable resource) {
    //设置资源到ImageView
    view.setImageDrawable(resource);
}
  • 最后,把Drawbale,设置到了ImageView上。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容