3. In-depth understanding of Glide source code

foreword

In the first two articles, we analyzed in detail the core source code of Android’s network underlying framework OKHttp and the packaging framework Retrofit. If you don’t understand the internal mechanism of OKHttp or Retrofit, you can look at the source code analysis of Android’s mainstream three-party libraries (1. In-depth understanding of OKHttp source code ) and Android mainstream three-party library source code analysis (2. In-depth understanding of Retrofit source code) . In this article, we will deeply analyze the source code loading process of Glide, the most widely used image loading framework for Android at present.

1. Basic use process

The most basic use process of Glide is the following line of code, and all other extended extra functions are added on the basis of its builder chain call.

GlideApp.with(context).load(url).into(iv);

Among them, GlideApp is automatically generated by the annotation processor. To use GlideApp, you must first configure the AppGlideModule module of the application. It can be empty configuration, or you can add specified configuration according to the actual situation.

@GlideModule
public class MyAppGlideModule extends AppGlideModule {
    
    

    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
    
    
        // 实际使用中根据情况可以添加如下配置
        <!--builder.setDefaultRequestOptions(new RequestOptions().format(DecodeFormat.PREFER_RGB_565));-->
        <!--int memoryCacheSizeBytes = 1024 * 1024 * 20;-->
        <!--builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));-->
        <!--int bitmapPoolSizeBytes = 1024 * 1024 * 30;-->
        <!--builder.setBitmapPool(new LruBitmapPool(bitmapPoolSizeBytes));-->
        <!--int diskCacheSizeBytes = 1024 * 1024 * 100;-->
        <!--builder.setDiskCache(new InternalCacheDiskCacheFactory(context, diskCacheSizeBytes));-->
    }
}

Next, this article will analyze and explain in detail the process of Glide loading network images for the latest source code version V4.8.0 of Glide, and strive to let readers and friends know what it is and why.

Two, GlideApp.with(context) source code details

First of all, this Glide frame diagram drawn by艽野气梦gives us a preliminary understanding of the overall framework of Glide.

image

Starting from the line of code GlideApp.with, the internal main line execution flow is as follows.

1、GlideApp#with

return (GlideRequests) Glide.with(context);

2、Glide#with

return getRetriever(context).get(context);

return Glide.get(context).getRequestManagerRetriever();

// 外部使用了双重检锁的同步方式确保同一时刻只执一次Glide的初始化
checkAndInitializeGlide(context);

initializeGlide(context);

// 最终执行到Glide的另一个重载方法
initializeGlide(context, new GlideBuilder());

@SuppressWarnings("deprecation")
  private static void initializeGlide(@NonNull Context   context, @NonNull GlideBuilder builder) {
    
    
    Context applicationContext =     context.getApplicationContext();
    // 1、获取前面应用中带注解的GlideModule
    GeneratedAppGlideModule annotationGeneratedModule =     getAnnotationGeneratedGlideModules();
    // 2、如果GlideModule为空或者可配置manifest里面的标志为true,则获取manifest里面
    // 配置的GlideModule模块(manifestModules)。
    List<com.bumptech.glide.module.GlideModule>     manifestModules = Collections.emptyList();
    if (annotationGeneratedModule == null ||     annotationGeneratedModule.isManifestParsingEnabled(    )) {
    
    
      manifestModules = new   ManifestParser(applicationContext).parse();
    }

    ...

    RequestManagerRetriever.RequestManagerFactory     factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManag    erFactory() : null;
    builder.setRequestManagerFactory(factory);
    for (com.bumptech.glide.module.GlideModule module :     manifestModules) {
    
    
      module.applyOptions(applicationContext, builder);
    }
    if (annotationGeneratedModule != null) {
    
    
      annotationGeneratedModule.applyOptions(applicatio  nContext, builder);
    }
    // 3、初始化各种配置信息
    Glide glide = builder.build(applicationContext);
    // 4、把manifestModules以及annotationGeneratedModule里面的配置信息放到builder
    // 里面(applyOptions)替换glide默认组件(registerComponents)
    for (com.bumptech.glide.module.GlideModule module :     manifestModules) {
    
    
      module.registerComponents(applicationContext,   glide, glide.registry);
    }
    if (annotationGeneratedModule != null) {
    
    
      annotationGeneratedModule.registerComponents(appl  icationContext, glide, glide.registry);
    }
    applicationContext.registerComponentCallbacks(glide    );
    Glide.glide = glide;
}

3、GlideBuilder#build

@NonNull
  Glide build(@NonNull Context context) {
    
    
    // 创建请求图片线程池sourceExecutor
    if (sourceExecutor == null) {
    
    
      sourceExecutor =   GlideExecutor.newSourceExecutor();
    }

    // 创建硬盘缓存线程池diskCacheExecutor
    if (diskCacheExecutor == null) {
    
    
      diskCacheExecutor =   GlideExecutor.newDiskCacheExecutor();
    }

    // 创建动画线程池animationExecutor
    if (animationExecutor == null) {
    
    
      animationExecutor =   GlideExecutor.newAnimationExecutor();
    }

    if (memorySizeCalculator == null) {
    
    
      memorySizeCalculator = new   MemorySizeCalculator.Builder(context).build();
    }

    if (connectivityMonitorFactory == null) {
    
    
      connectivityMonitorFactory = new   DefaultConnectivityMonitorFactory();
    }

    if (bitmapPool == null) {
    
    
      // 依据设备的屏幕密度和尺寸设置各种pool的size
      int size =   memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) {
    
    
        // 创建图片线程池LruBitmapPool,缓存所有被释放的bitmap
        // 缓存策略在API大于19时,为SizeConfigStrategy,小于为AttributeStrategy。
        // 其中SizeConfigStrategy是以bitmap的size和config为key,value为bitmap的HashMap
        bitmapPool = new LruBitmapPool(size);
      } else {
    
    
        bitmapPool = new BitmapPoolAdapter();
      }
    }

    // 创建对象数组缓存池LruArrayPool,默认4M
    if (arrayPool == null) {
    
    
      arrayPool = new   LruArrayPool(memorySizeCalculator.getArrayPoolSiz  eInBytes());
    }

    // 创建LruResourceCache,内存缓存
    if (memoryCache == null) {
    
    
      memoryCache = new   LruResourceCache(memorySizeCalculator.getMemoryCa  cheSize());
    }

    if (diskCacheFactory == null) {
    
    
      diskCacheFactory = new   InternalCacheDiskCacheFactory(context);
    }

    // 创建任务和资源管理引擎(线程池,内存缓存和硬盘缓存对象)
    if (engine == null) {
    
    
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(  ),
              GlideExecutor.newAnimationExecutor(),
              isActiveResourceRetentionAllowed);
    }
    
    RequestManagerRetriever requestManagerRetriever =
    new RequestManagerRetriever(requestManagerFactor
    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions);
}

4. Glide#Glide construction method

Glide(...) {
    
    
    ...
    // 注册管理任务执行对象的类(Registry)
    // Registry是一个工厂,而其中所有注册的对象都是一个工厂员工,当任务分发时,
    // 根据当前任务的性质,分发给相应员工进行处理
    registry = new Registry();
    
    ...
    
    // 这里大概有60余次的append或register员工组件(解析器、编解码器、工厂类、转码类等等组件)
    registry
    .append(ByteBuffer.class, new ByteBufferEncoder())
    .append(InputStream.class, new StreamEncoder(arrayPool))
    
    // 根据给定子类产出对应类型的target(BitmapImageViewTarget / DrawableImageViewTarget)
    ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
    
    glideContext =
        new GlideContext(
            context,
            arrayPool,
            registry,
            imageViewTargetFactory,
            defaultRequestOptions,
            defaultTransitionOptions,
            engine,
            logLevel);
}

5、RequestManagerRetriever#get

@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)) {
    
    
    // 如果当前线程是主线程且context不是Application走相应的get重载方法
    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());
    }
  }

  // 否则直接将请求与ApplicationLifecycle关联
  return getApplicationManager(context);
}

To summarize here, when the currently incoming context is application or the current thread is a child thread, the life cycle of the request is associated with ApplicationLifecycle, otherwise, when the context is FragmentActivity or Fragment, add a SupportFragment (SupportRequestManagerFragment) to the current component, and the context is Activity , add a Fragment(RequestManagerFragment) to the current component.

6. Summary of GlideApp#with

1. Initialize various configuration information (including cache, request thread pool, size, image format, etc.) and glide objects.
2. Bind the glide request with the life cycle of application/SupportFragment/Fragment.
Here we review the execution flow of the with method.

image

3. Detailed explanation of load(url) source code

1、GlideRequest(RequestManager)#load

return (GlideRequest<Drawable>) super.load(string);

return asDrawable().load(string);

// 1、asDrawable部分
return (GlideRequest<Drawable>) super.asDrawable();

return as(Drawable.class);

// 最终返回了一个GlideRequest(RequestManager的子类)
return new GlideRequest<>(glide, this, resourceClass, context);

// 2、load部分
return (GlideRequest<TranscodeType>) super.load(string);

return loadGeneric(string);

@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    
    
    // model则为设置的url
    this.model = model;
    // 记录url已设置
    isModelSet = true;
    return this;
}

It can be seen that the source code of the load part is very simple, that is, the mode (url) to be requested is set for GlideRequest (RequestManager), and the status of the url is recorded.

Here, let's look at the execution flow of the load method.

image

4. Detailed explanation of into(iv) source code

Forewarning ahead, the real complications begin.

1、RequestBuilder.into

@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.
    switch (view.getScaleType()) {
    
    
      // 这个RequestOptions里保存了要设置的scaleType,Glide自身封装了CenterCrop、CenterInside、
      // FitCenter、CenterInside四种规格。
      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是指的drawable或bitmap
  return into(
      glideContext.buildImageViewTarget(view,     transcodeClass),
      /*targetListener=*/ null,
      requestOptions);
}

2、GlideContext#buildImageViewTarget

return imageViewTargetFactory.buildTarget(imageView, transcodeClass);

3、ImageViewTargetFactory#buildTarget

@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z>   buildTarget(@NonNull ImageView view,
    @NonNull Class<Z> clazz) {
    
    
  // 返回展示Bimtap/Drawable资源的目标对象
  if (Bitmap.class.equals(clazz)) {
    
    
    return (ViewTarget<ImageView, Z>) new   BitmapImageViewTarget(view);
  } else if (Drawable.class.isAssignableFrom(clazz))     {
    
    
    return (ViewTarget<ImageView, Z>) new   DrawableImageViewTarget(view);
  } else {
    
    
    throw new IllegalArgumentException(
        "Unhandled class: " + clazz + ", try   .as*(Class).transcode(ResourceTranscoder)");
  }
}

It can be seen that Glide only maintains two targets internally, one is BitmapImageViewTarget, and the other is DrawableImageViewTarget, and then continue to deepen.

4、RequestBuilder#into

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType>   targetListener,
      @NonNull RequestOptions options) {
    
    
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
    
    
      throw new IllegalArgumentException("You must call   #load() before calling #into()");
    }

    options = options.autoClone();
    // 分析1.建立请求
    Request request = buildRequest(target,     targetListener, options);

    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousReques    t(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).isRunni  ng()) {
    
    
        // 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;
    }
    
    requestManager.clear(target);
    target.setRequest(request);
    // 分析2.真正追踪请求的地方
    requestManager.track(target, request);

    return target;
}

// 分析1
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);

// 分析1
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(异常处理对象)
      errorRequestCoordinator = new   ErrorRequestCoordinator(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }

    // 递归建立缩略图请求
    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions);

    if (errorRequestCoordinator == null) {
    
    
      return mainRequest;
    }

    ...
    
    Request errorRequest =     errorBuilder.buildRequestRecursive(
        target,
        targetListener,
        errorRequestCoordinator,
        errorBuilder.transitionOptions,
        errorBuilder.requestOptions.getPriority(),
        errorOverrideWidth,
        errorOverrideHeight,
        errorBuilder.requestOptions);
    errorRequestCoordinator.setRequests(mainRequest,     errorRequest);
    return errorRequestCoordinator;
}

// 分析1
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.
      
      
      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(ThumbnailRequestCoordinator)是作为两者的协调者,
      // 能够同时加载缩略图和正常的图的请求
      coordinator.setRequests(fullRequest, thumbRequest);
      return coordinator;
    } else if (thumbSizeMultiplier != null) {
    
    
      // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
      // 当设置了缩略的比例thumbSizeMultiplier(0 ~  1)时,
      // 不需要递归建立缩略图请求
      ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
      Request fullRequest =
          obtainRequest(
              target,
              targetListener,
              requestOptions,
              coordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight);
      RequestOptions thumbnailOptions = requestOptions.clone()
          .sizeMultiplier(thumbSizeMultiplie
      Request thumbnailRequest =
          obtainRequest(
              target,
              targetListener,
              thumbnailOptions,
              coordinator,
              transitionOptions,
              getThumbnailPriority(priority),
              overrideWidth,
              overrideHeigh
      coordinator.setRequests(fullRequest, thumbnailRequest);
      return coordinator;
    } else {
    
    
      // Base case: no thumbnail.
      // 没有缩略图请求时,直接获取一个正常图请求
      return obtainRequest(
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight);
    }
}

private Request obtainRequest(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      RequestOptions requestOptions,
      RequestCoordinator requestCoordinator,
      TransitionOptions<?, ? super TranscodeType>   transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight) {
    
    
    // 最终实际返回的是一个SingleRequest对象(将制定的资源加载进对应的Target
    return SingleRequest.obtain(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory());
}

From the above source code analysis, we can see that we have established a request in the buildRequest() method at Analysis 1, and can request thumbnails and normal images at most at the same time. Finally, we call the requestManager.track(target, request) method, and then look at See what's going on in the track.

5、RequestManager#track

// 分析2
void track(@NonNull Target<?> target, @NonNull Request request) {
    
    
    // 加入一个target目标集合(Set)
    targetTracker.track(target);
    
    requestTracker.runRequest(request);
}

6、RequestTracker#runRequest

/**
* Starts tracking the given request.
*/
// 分析2
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");
      }
      // 否则清空请求,加入延迟请求队列(为了对这些请求维持一个强引用,使用了ArrayList实现)
      pendingRequests.add(request);
    }
}

7、SingleRequest#begin

// 分析2
@Override
public void begin() {
    
    
  
  ...
  
  if (model == null) {
    
    
  
    ...
    // model(url)为空,回调加载失败
    onLoadFailed(new GlideException("Received null   model"), logLevel);
    return;
  }

  if (status == Status.RUNNING) {
    
    
    throw new IllegalArgumentException("Cannot   restart a running request");
  }

 
  if (status == Status.COMPLETE) {
    
    
    onResourceReady(resource,   DataSource.MEMORY_CACHE);
    return;
  }

  status = Status.WAITING_FOR_SIZE;
  if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
    
    
    // 当使用override() API为图片指定了一个固定的宽高时直接执行onSizeReady,
    // 最终的核心处理位于onSizeReady
    onSizeReady(overrideWidth, overrideHeight);
  } else {
    
    
    // 根据imageView的宽高算出图片的宽高,最终也会走到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));
  }
}

Starting from requestManager.track(target, request), it will eventually execute to the onSizeReady of the SingleRequest#begin() method. You can guess (because only the preloading thumbnails are processed later), the real request starts here. Let's go in and find out~

8、SingleRequest#onSizeReady

// 分析2
@Override
public void onSizeReady(int width, int height) {
    
    
  stateVerifier.throwIfRecycled();
  
  ...
  
  status = Status.RUNNING;

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

  ...
  
  // 根据给定的配置进行加载,engine是一个负责加载、管理活跃和缓存资源的引擎类
  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.getUseUnlimitedSourceGeneratorsP    ool(),
      requestOptions.getUseAnimationPool(),
      requestOptions.getOnlyRetrieveFromCache(),
      this);

  ...
}

I finally saw the Engine class, and I feel that I am not far from success. Continue~

9、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) {
    
    
  
  ...

  // 先从弱引用中查找,如果有的话回调onResourceReady并直接返回
  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;
  }

  // 没有再从内存中查找,有的话会取出并放到ActiveResources(内部维护的弱引用缓存map)里面
  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;
  }

  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(decodejob的回调类,管理下载过程以及状态)
  EngineJob<R> engineJob =
      engineJobFactory.build(
          key,
          isMemoryCacheable,
          useUnlimitedSourceExecutorPool,
          useAnimationPool,
          onlyRetrieveFromCache);

  // 创建解析工作对象
  DecodeJob<R> decodeJob =
      decodeJobFactory.build(
          glideContext,
          model,
          key,
          signature,
          width,
          height,
          resourceClass,
          transcodeClass,
          priority,
          diskCacheStrategy,
          transformations,
          isTransformationRequired,
          isScaleOnlyOrNoTransform,
          onlyRetrieveFromCache,
          options,
          engineJob);

  // 放在Jobs内部维护的HashMap中
  jobs.put(key, engineJob);

  // 关注点8 后面分析会用到
  // 注册ResourceCallback接口
  engineJob.addCallback(cb);
  // 内部开启线程去请求
  engineJob.start(decodeJob);

  if (VERBOSE_IS_LOGGABLE) {
    
    
    logWithTimeAndKey("Started new load", startTime,   key);
  }
  return new LoadStatus(cb, engineJob);
}

public void start(DecodeJob<R> decodeJob) {
    
    
    this.decodeJob = decodeJob;
    // willDecodeFromCache方法内部根据不同的阶段stage,如果是RESOURCE_CACHE/DATA_CACHE则返回true,使用diskCacheExecutor,否则调用getActiveSourceExecutor,内部会根据相应的条件返回sourceUnlimitedExecutor/animationExecutor/sourceExecutor
    GlideExecutor executor =   
    decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
}

It can be seen that eventually the Engine (engine) class will execute its own start method internally, and it will use different thread pools according to different configurations to use diskCacheExecutor/sourceUnlimitedExecutor/animationExecutor/sourceExecutor to execute the final decoding task decodeJob.

10、DecodeJob#run

runWrapped();

private void runWrapped() {
    
    
    switch (runReason) {
    
    
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);
        // 关注点1
        currentGenerator = getNextGenerator();
        // 关注点2 内部会调用相应Generator的startNext()
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        // 关注点3 将获取的数据解码成对应的资源
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized     run reason: " + runReason);
    }
}
    
// 关注点1,完整情况下,会异步依次生成这里的ResourceCacheGenerator、DataCacheGenerator和SourceGenerator对象,并在之后执行其中的startNext()
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);
    }
}

11、SourceGenerator#startNext

// 关注点2
@Override
public boolean startNext() {
    
    
  // dataToCache数据不为空的话缓存到硬盘(第一执行该方法是不会调用的)
  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()) {
    
    
    // 关注点4 getLoadData()方法内部会在modelLoaders里面找到ModelLoder对象
    // (每个Generator对应一个ModelLoader),
    // 并使用modelLoader.buildLoadData方法返回一个loadData列表
    loadData =   helper.getLoadData().get(loadDataListIndex++);
    if (loadData != null
        && (helper.getDiskCacheStrategy().isDataCache  able(loadData.fetcher.getDataSource())
        || helper.hasLoadPath(loadData.fetcher.getDat  aClass()))) {
    
    
      started = true;
      // 关注点6 通过loadData对象的fetcher对象(有关注点3的分析可知其实现类为HttpUrlFetcher)的
      // loadData方法来获取图片数据
      loadData.fetcher.loadData(helper.getPriority(),     this);
    }
  }
  return started;
}

12、DecodeHelper#getLoadData

List<LoadData<?>> getLoadData() {
    
    
    if (!isLoadDataSet) {
    
    
      isLoadDataSet = true;
      loadData.clear();
      List<ModelLoader<Object, ?>> modelLoaders =   glideContext.getRegistry().getModelLoaders(model)  ;
      //noinspection ForLoopReplaceableByForEach to   improve perf
      for (int i = 0, size = modelLoaders.size(); i <   size; i++) {
    
    
        ModelLoader<Object, ?> modelLoader =     modelLoaders.get(i);
        // 注意:这里最终是通过HttpGlideUrlLoader的buildLoadData获取到实际的loadData对象
        LoadData<?> current =
            modelLoader.buildLoadData(model, width,     height, options);
        if (current != null) {
    
    
          loadData.add(current);
        }
      }
    }
    return loadData;
}

13、HttpGlideUrlLoader#buildLoadData

@Override
public LoadData<InputStream> buildLoadData(@NonNull   GlideUrl model, int width, int height,
    @NonNull Options options) {
    
    
  // GlideUrls memoize parsed URLs so caching them     saves a few object instantiations and time
  // spent parsing urls.
  GlideUrl url = model;
  if (modelCache != null) {
    
    
    url = modelCache.get(model, 0, 0);
    if (url == null) {
    
    
      // 关注点5
      modelCache.put(model, 0, 0, model);
      url = model;
    }
  }
  int timeout = options.get(TIMEOUT);
  // 注意,这里创建了一个DataFetcher的实现类HttpUrlFetcher
  return new LoadData<>(url, new HttpUrlFetcher(url,     timeout));
}

// 关注点5
public void put(A model, int width, int height, B value) {
    
    
    ModelKey<A> key = ModelKey.get(model, width,     height);
    // 最终是通过LruCache来缓存对应的值,key是一个ModelKey对象(由model、width、height三个属性组成)
    cache.put(key, value);
}

From the analysis here, we understand that HttpUrlFetcher is actually the final request executor, and we know that Glide will use LruCache to cache the parsed url, so that the time for parsing the url can be saved later.

14、HttpUrlFetcher#loadData

@Override
public void loadData(@NonNull Priority priority,
    @NonNull DataCallback<? super InputStream>   callback) {
    
    
  long startTime = LogTime.getLogTime();
  try {
    
    
    // 关注点6
    // loadDataWithRedirects内部是通过HttpURLConnection网络请求数据
    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));
    }
  }
}
    
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
  Map<String, String> headers) throws IOException {
    
    
    
    ...

    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();
    // 只要是2xx形式的状态码则判断为成功
    if (isHttpOk(statusCode)) {
    
    
      // 从urlConnection中获取资源流
      return getStreamForSuccessfulRequest(urlConnection);
    } else if (isHttpRedirect(statusCode)) {
    
    
    
      ...
      
      // 重定向请求
      return loadDataWithRedirects(redirectUrl, redirects + 1, url,   headers);
    } else if (statusCode == INVALID_STATUS_CODE) {
    
    
      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.getInputStr  eam(), contentLength);
    } else {
    
    
      if (Log.isLoggable(TAG, Log.DEBUG)) {
    
    
        Log.d(TAG, "Got non empty content encoding: " +     urlConnection.getContentEncoding());
      }
      stream = urlConnection.getInputStream();
    }
    return stream;
}

In the loadDataWithRedirects of the HttpUrlFetcher#loadData method, Glide makes a request through the native HttpURLConnection, and calls the getStreamForSuccessfulRequest() method to obtain the final image stream.

15、DecodeJob#run

After we request the corresponding stream through the loadData() method of HtttpUrlFetcher, we must also process the stream to get the final resource we want. Here we return to point 3 of the DecodeJob#run method in step 10. This line of code will decode the stream.

decodeFromRetrievedData();

Next, continue to look at his internal processing.

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 {
    
    
      //  核心代码 
      // 从数据中解码得到资源
      resource = decodeFromData(currentFetcher, currentData,   currentDataSource);
    } catch (GlideException e) {
    
    
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
    
    
      // 关注点8 
      // 编码和发布最终得到的Resource<Bitmap>对象
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
    
    
      runGenerators();
    }
}

 private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
  DataSource dataSource) throws GlideException {
    
    
    try {
    
    
      if (data == null) {
    
    
        return null;
      }
      long startTime = LogTime.getLogTime();
      // 核心代码
      // 进一步包装了解码方法
      Resource<R> result = decodeFromFetcher(data, dataSource);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
    
    
        logWithTimeAndKey("Decoded result " + result, startTime);
      }
      return result;
    } finally {
    
    
      fetcher.cleanup();
    }
}

@SuppressWarnings("unchecked")
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
  throws GlideException {
    
    
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
    // 核心代码
    // 将解码任务分发给LoadPath
    return runLoadPath(data, dataSource, path);

private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource,
  LoadPath<Data, ResourceType, R> path) throws GlideException {
    
    
    Options options = getOptionsWithHardwareConfig(dataSource);
    // 将数据进一步包装
    DataRewinder<Data> rewinder =     glideContext.getRegistry().getRewinder(data);
    try {
    
    
      // ResourceType in DecodeCallback below is required for   compilation to work with gradle.
      // 核心代码
      // 将解码任务分发给LoadPath
      return path.load(
          rewinder, options, width, height, new   DecodeCallback<ResourceType>(dataSource));
    } finally {
    
    
      rewinder.cleanup();
    }
}

16、LoadPath#load

public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width,
  int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException {
    
    
List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
try {
    
    
  // 核心代码
  return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
} finally {
    
    
  listPool.release(throwables);
}
private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder,
      @NonNull Options options,
      int width, int height, DecodePath.DecodeCallback<ResourceType>   decodeCallback,
      List<Throwable> exceptions) throws GlideException {
    
    
    Resource<Transcode> result = null;
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = decodePaths.size(); i < size; i++) {
    
    
      DecodePath<Data, ResourceType, Transcode> path =   decodePaths.get(i);
      try {
    
    
        // 核心代码
        // 将解码任务又进一步分发给DecodePath的decode方法去解码
        result = path.decode(rewinder, width, height, options,     decodeCallback);
      } catch (GlideException e) {
    
    
        exceptions.add(e);
      }
      if (result != null) {
    
    
        break;
      }
    }

    if (result == null) {
    
    
      throw new GlideException(failureMessage, new   ArrayList<>(exceptions));
    }

    return result;
}

17、DecodePath#decode

public Resource<Transcode> decode(DataRewinder<DataType> rewinder,     int width, int height,
      @NonNull Options options, DecodeCallback<ResourceType> callback)   throws GlideException {
    
    
    // 核心代码
    // 继续调用DecodePath的decodeResource方法去解析出数据
    Resource<ResourceType> decoded = decodeResource(rewinder, width,     height, options);
    Resource<ResourceType> transformed =     callback.onResourceDecoded(decoded);
    return transcoder.transcode(transformed, options);

@NonNull
private Resource<ResourceType> decodeResource(DataRewinder<DataType>   rewinder, int width,
    int height, @NonNull Options options) throws GlideException {
    
    
  List<Throwable> exceptions =     Preconditions.checkNotNull(listPool.acquire());
  try {
    
    
    // 核心代码
    return decodeResourceWithList(rewinder, width, height, options,   exceptions);
  } finally {
    
    
    listPool.release(exceptions);
  }
}

@NonNull
private Resource<ResourceType>   decodeResourceWithList(DataRewinder<DataType> rewinder, int width,
    int height, @NonNull Options options, List<Throwable> exceptions)   throws GlideException {
    
    
  Resource<ResourceType> result = null;
  //noinspection ForLoopReplaceableByForEach to improve perf
  for (int i = 0, size = decoders.size(); i < size; i++) {
    
    
    ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
    try {
    
    
      DataType data = rewinder.rewindAndGet();
      if (decoder.handles(data, options)) {
    
    
        // 获取包装的数据
        data = rewinder.rewindAndGet();
        // 核心代码 
        // 根据DataType和ResourceType的类型分发给不同的解码器Decoder
        result = decoder.decode(data, width, height, options);
      }
    } catch (IOException | RuntimeException | OutOfMemoryError e) {
    
    
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
    
    
        Log.v(TAG, "Failed to decode data for " + decoder, e);
      }
      exceptions.add(e);
    }

    if (result != null) {
    
    
      break;
    }
  }

  if (result == null) {
    
    
    throw new GlideException(failureMessage, new   ArrayList<>(exceptions));
  }
  return result;
}

It can be seen that after a series of nested calls, the code of decoder.decode() is finally executed. decode is a ResourceDecoder<DataType, ResourceType> interface (resource decoder), and it will have different values ​​depending on the DataType and ResourceType. Implementation class, the implementation class here is ByteBufferBitmapDecoder, let's take a look at the internal decoding process of this decoder.

18、ByteBufferBitmapDecoder#decode

/**
 * Decodes {@link android.graphics.Bitmap Bitmaps} from {@link    java.nio.ByteBuffer ByteBuffers}.
 */
public class ByteBufferBitmapDecoder implements     ResourceDecoder<ByteBuffer, Bitmap> {
    
    
  
  ...

  @Override
  public Resource<Bitmap> decode(@NonNull ByteBuffer source, int width,   int height,
      @NonNull Options options)
      throws IOException {
    
    
    InputStream is = ByteBufferUtil.toStream(source);
    // 核心代码
    return downsampler.decode(is, width, height, options);
  }
}

It can be seen that in the end, a downsampler is used, which is a compressor, mainly for decoding, compressing, rounding and other processing on the stream.

19、DownSampler#decode

public Resource<Bitmap> decode(InputStream is, int outWidth, int outHeight,
  Options options) throws IOException {
    
    
    return decode(is, outWidth, outHeight, options, EMPTY_CALLBACKS);
}

 @SuppressWarnings({
    
    "resource", "deprecation"})
public Resource<Bitmap> decode(InputStream is, int requestedWidth, int requestedHeight,
      Options options, DecodeCallbacks callbacks) throws IOException {
    
    
    Preconditions.checkArgument(is.markSupported(), "You must provide an     InputStream that supports"
        + " mark()");

    ...

    try {
    
    
      // 核心代码
      Bitmap result = decodeFromWrappedStreams(is, bitmapFactoryOptions,
          downsampleStrategy, decodeFormat, isHardwareConfigAllowed,   requestedWidth,
          requestedHeight, fixBitmapToRequestedDimensions, callbacks);
      // 关注点7   
      // 解码得到Bitmap对象后,包装成BitmapResource对象返回,
      // 通过内部的get方法得到Resource<Bitmap>对象
      return BitmapResource.obtain(result, bitmapPool);
    } finally {
    
    
      releaseOptions(bitmapFactoryOptions);
      byteArrayPool.put(bytesForOptions);
    }
}

private Bitmap decodeFromWrappedStreams(InputStream is,
      BitmapFactory.Options options, DownsampleStrategy downsampleStrategy,
      DecodeFormat decodeFormat, boolean isHardwareConfigAllowed, int requestedWidth,
      int requestedHeight, boolean fixBitmapToRequestedDimensions,
      DecodeCallbacks callbacks) throws IOException {
    
    
    
    // 省去计算压缩比例等一系列非核心逻辑
    ...
    
    // 核心代码
    Bitmap downsampled = decodeStream(is, options, callbacks, bitmapPool);
    callbacks.onDecodeComplete(bitmapPool, downsample
    
    // Bimtap旋转处理
    ...
    
    return rotated;

private static Bitmap decodeStream(InputStream is,     BitmapFactory.Options options,
      DecodeCallbacks callbacks, BitmapPool bitmapPool) throws   IOException {
    
    
    
    ...
    
    TransformationUtils.getBitmapDrawableLock().lock();
    try {
    
    
      // 核心代码
      result = BitmapFactory.decodeStream(is, null, options);
    } catch (IllegalArgumentException e) {
    
    
      ...
    } finally {
    
    
      TransformationUtils.getBitmapDrawableLock().unlock();
    }

    if (options.inJustDecodeBounds) {
    
    
      is.reset();
    }
    return result;
}

From the above source code process, we know that in the end, BitmapFactory.decodeStream() is used in DownSampler's decodeStream() method to get the Bitmap object. Then, let's analyze how the picture is displayed. Let's go back to the DownSampler#decode method in step 19 and see point 7. Here, the Bitmap is packaged into a BitmapResource object and returned. The Resource object can be obtained through the internal get method, and then Go back to the DecodeJob#run method in step 15, which uses the notifyEncodeAndRelease() method to release the Resource object.

20、DecodeJob#notifyEncodeAndRelease

private void notifyEncodeAndRelease(Resource<R> resource, DataSource     dataSource) {
    
    
 
    ...

    notifyComplete(result, dataSource);

    ...
    
}

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

As can be seen from the source code of EngineJob above, it implements the interface DecodeJob.CallBack.

class EngineJob<R> implements DecodeJob.Callback<R>,
    Poolable {
    
    
    ...
}

21、EngineJob#onResourceReady

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

private static class MainThreadCallback implements Handler.Callback{
    
    

    ...

    @Override
    public boolean handleMessage(Message message) {
    
    
      EngineJob<?> job = (EngineJob<?>) message.obj;
      switch (message.what) {
    
    
        case MSG_COMPLETE:
          // 核心代码
          job.handleResultOnMainThread();
          break;
        ...
      }
      return true;
    }
}

From the above source code, we can see that the thread is switched through the main thread Handler object, and then the handleResultOnMainThread method is called on the main thread.

@Synthetic
void handleResultOnMainThread() {
    
    
  ...

  //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();
      cb.onResourceReady(engineResource, dataSource);
    }
  }
 
  ...
}

Here, all ResourceCallback methods are called through a loop, let us go back to the line of code 8 of the Engine#load method in step 9, where the ResourceCallback is registered, and the engine in the SingleRequest#onSizeReady method is displayed in step 8. In load, we see the last parameter, which is passed in. It can be understood that the implementation class of cb in engineJob.addCallback(cb) is SingleRequest. Next, let's look at the SingleRequest's onResourceReady method.

22、SingleRequest#onResourceReady

/**
 * A callback method that should never be invoked directly.
 */
@SuppressWarnings("unchecked")
@Override
public void onResourceReady(Resource<?> resource, DataSource   dataSource) {
    
    
  ...
  
  // 从Resource<Bitmap>中得到Bitmap对象
  Object received = resource.get();
  
  ...
  
  onResourceReady((Resource<R>) resource, (R) received, dataSource);
}

private void onResourceReady(Resource<R> resource, R resultDataSource dataSource) {
    
    

    ...

    try {
    
    
      ...

      if (!anyListenerHandledUpdatingTarget) {
    
    
        Transition<? super R> animation =
            animationFactory.build(dataSource, isFirstResource);
        // 核心代码
        target.onResourceReady(result, animation);
      }
    } finally {
    
    
      isCallingCallbacks = false;
    }

    notifyLoadSuccess();
}

In the SingleRequest#onResourceReady method, the target.onResourceReady(result, animation) method is called. The target here is actually the BitmapImageViewTarget we established in the into method. Seeing the BitmapImageViewTarget class, we did not find the onResourceReady method, but we learned from it The onResourceReady method is found in the subclass of ImageViewTarget, from here we continue to look down.

23、ImageViewTarget#onResourceReady

public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
implements Transition.ViewAdapter {
    
    

    
    @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(resource);
        maybeUpdateAnimatable(resource);
    }
    
    // 核心代码
    protected abstract void setResource(@Nullable Z resource);
}

Here we are returning to the setResource method of BitmapImageViewTarget, and we finally see that the Bitmap is set to the current imageView.

public class BitmapImageViewTarget extends ImageViewTarget<Bitmap> {
    
    

    ...
    
    
    @Override
    protected void setResource(Bitmap resource) {
    
    
      view.setImageBitmap(resource);
    }
}

At this point, our analysis is over. From the above analysis, we can see that Glide puts most of the logic processing in the last into method, which requires more than 20 analysis steps to process the requested image stream and decode the image. , and finally set to the corresponding imageView.

Finally, here is a complete Glide loading flowchart that I spent several hours drawing. It is very precious. You can carefully sort out the main process of Glide again.

V. Summary

At this point, the analysis of Glide's entire loading process is over. It can be seen that the core logic of Glide is gathered in the into() method. The design inside it is exquisite and complex. The source code analysis of this part is very time-consuming. However, If you really go deep into it step by step, you may have an epiphany on the road to Android advancement. At present, Android mainstream three-party library source code analysis series has carried out detailed source code analysis on the network library (OkHttp, Retrofit) and image loading library (Glide). Next, it will conduct an in-depth analysis on the core source code of the database framework GreenDao. Please look forward to it~

Reference link:

1. Glide V4.8.0 source code

2. Understand the execution process of Glide from the perspective of source code

3. Glide source code analysis

Reprint: https://juejin.cn/post/6844904049595121672

Guess you like

Origin blog.csdn.net/gqg_guan/article/details/129123271#comments_27548947