3. Comprensión profunda del código fuente de Glide

prefacio

En los dos primeros artículos, analizamos en detalle el código fuente central del marco subyacente de la red de Android OKHttp y el marco de empaquetado Retrofit. Si no comprende el mecanismo interno de OKHttp o Retrofit, puede consultar el análisis del código fuente de Android. Bibliotecas principales de tres partes (1. Comprensión profunda del código fuente de OKHttp ) y análisis del código fuente de la biblioteca principal de tres partes de Android (2. Comprensión profunda del código fuente de Retrofit) . En este artículo analizaremos en profundidad el proceso de carga de código fuente de Glide, el framework de carga de imágenes para Android más utilizado en la actualidad.

1. Proceso de uso básico

El proceso de uso más básico de Glide es la siguiente línea de código, y todas las demás funciones adicionales extendidas se agregan en función de su llamada de cadena de constructor.

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

Entre ellos, GlideApp es generado automáticamente por el procesador de anotaciones. Para usar GlideApp, primero debe configurar el módulo AppGlideModule de la aplicación. Puede ser una configuración vacía o puede agregar una configuración específica de acuerdo con la situación real.

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

A continuación, este artículo analizará y explicará en detalle el proceso de carga de imágenes de red de Glide para la última versión del código fuente V4.8.0 de Glide, y se esforzará por que los lectores y amigos sepan qué es y por qué.

Dos, detalles del código fuente de GlideApp.with (contexto)

En primer lugar, este diagrama de marco Glide dibujado por艽野气梦nos brinda una comprensión preliminar del marco general de Glide.

imagen

A partir de la línea de código GlideApp.with, el flujo de ejecución de la línea principal interna es el siguiente.

1、GlideApp#con

return (GlideRequests) Glide.with(context);

2, deslizamiento # con

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#construcción

@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. Método de construcción Glide#Glide

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

Para resumir aquí, cuando el contexto entrante actual es una aplicación o el subproceso actual es un subproceso secundario, el ciclo de vida de la solicitud se asocia con ApplicationLifecycle; de ​​lo contrario, cuando el contexto es FragmentActivity o Fragment, agregue un SupportFragment (SupportRequestManagerFragment) al actual y el contexto es Activity , agregue un Fragment(RequestManagerFragment) al componente actual.

6. Resumen de GlideApp#with

1. Inicialice varios datos de configuración (incluida la memoria caché, el grupo de subprocesos de solicitud, el tamaño, el formato de la imagen, etc.) y los objetos deslizantes.
2. Vincule la solicitud de deslizamiento con el ciclo de vida de la aplicación/SupportFragment/Fragment.
Aquí revisamos el flujo de ejecución del método with.

imagen

3. Explicación detallada del código fuente de carga (url)

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

Se puede ver que el código fuente de la parte de carga es muy simple, es decir, se configura el modo (url) a solicitar para GlideRequest (RequestManager), y se registra el estado de la url.

Aquí, veamos el flujo de ejecución del método de carga.

imagen

4. Explicación detallada del código fuente into(iv)

Previo aviso, comienzan las verdaderas complicaciones.

1, RequestBuilder.

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

Se puede ver que Glide solo mantiene dos objetivos internamente, uno es BitmapImageViewTarget y el otro es DrawableImageViewTarget, y luego continúa profundizando.

4、RequestBuilder#en

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

Del análisis del código fuente anterior, podemos ver que hemos establecido una solicitud en el método buildRequest() en el Análisis 1, y podemos solicitar miniaturas e imágenes normales como máximo al mismo tiempo. Finalmente, llamamos al requestManager.track(target , solicitud) y, a continuación, consulte Ver lo que sucede en la pista.

5, RequestManager#seguimiento

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

6, Rastreador de solicitudes # ejecutar Solicitud

/**
* 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,Solicitud única#inicio

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

A partir de requestManager.track(objetivo, solicitud), eventualmente se ejecutará en el método onSizeReady del SingleRequest#begin(). Puede adivinar (porque solo las miniaturas de precarga se procesan más tarde), la solicitud real comienza aquí. Entremos y descúbrelo~

8, Solicitud única # en tamaño listo

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

  ...
}

Finalmente vi la clase Engine, y siento que no estoy lejos del éxito. Continuar~

9, carga del motor

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

Se puede ver que eventualmente la clase Engine (motor) ejecutará su propio método de inicio internamente, y usará diferentes grupos de subprocesos de acuerdo con diferentes configuraciones para usar diskCacheExecutor/sourceUnlimitedExecutor/animationExecutor/sourceExecutor para ejecutar la tarea de decodificación final decodeJob.

10, Decodificar trabajo #ejecutar

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, Generador de fuentes#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);
}

Del análisis aquí, entendemos que HttpUrlFetcher es en realidad el ejecutor final de la solicitud, y sabemos que Glide usará LruCache para almacenar en caché la URL analizada, de modo que el tiempo para analizar la URL se pueda guardar más tarde.

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

En el método loadDataWithRedirects del HttpUrlFetcher#loadData, Glide realiza una solicitud a través de la HttpURLConnection nativa y llama al método getStreamForSuccessfulRequest() para obtener el flujo de imagen final.

15, Decodificar trabajo #ejecutar

Después de solicitar el flujo correspondiente a través del método loadData() de HtttpUrlFetcher, también debemos procesar el flujo para obtener el recurso final que queremos. Aquí volvemos al punto 3 del método DecodeJob#run en el paso 10. Esta línea de código decodificará la transmisión.

decodeFromRetrievedData();

Luego, continúe observando su procesamiento interno.

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, ruta de carga # carga

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, ruta de decodificación # decodificación

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

Se puede ver que después de una serie de llamadas anidadas, finalmente se ejecuta el código de decoder.decode().decode es una interfaz ResourceDecoder<DataType, ResourceType> (decodificador de recursos), y tendrá diferentes valores dependiendo del DataType y ResourceType Clase de implementación, la clase de implementación aquí es ByteBufferBitmapDecoder, echemos un vistazo al proceso de decodificación interno de este decodificador.

18, ByteBufferBitmapDecoder#decodificación

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

Se puede ver que al final se usa un downsampler, que es un compresor, principalmente para decodificar, comprimir, redondear y otros procesamientos en la transmisión.

19 、 DownSampler # decodificación

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

Del proceso de código fuente anterior, sabemos que al final, BitmapFactory.decodeStream() se usa en el método decodeStream() de DownSampler para obtener el objeto Bitmap. Luego, analicemos cómo se muestra la imagen. Volvamos al método DownSampler#decode en el paso 19 y veamos el punto 7. Aquí, el mapa de bits se empaqueta en un objeto BitmapResource y se devuelve. El objeto Resource se puede obtener a través del get interno. y, a continuación, vuelva al método DecodeJob#run del paso 15, que utiliza el método notificarEncodeAndRelease() para liberar el objeto Resource.

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

Como se puede ver en el código fuente de EngineJob anterior, implementa la interfaz 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;
    }
}

A partir del código fuente anterior, podemos ver que el subproceso se cambia a través del objeto Handler del subproceso principal, y luego se llama al método handleResultOnMainThread en el subproceso principal.

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

Aquí, todos los métodos ResourceCallback se llaman a través de un bucle, volvamos a la línea de código 8 del método Engine#load en el paso 9, donde se registra ResourceCallback y se muestra el motor en el método SingleRequest#onSizeReady en el paso 8. En la carga, vemos el último parámetro, que se pasa. Se puede entender que la clase de implementación de cb en engineJob.addCallback(cb) es SingleRequest. A continuación, veamos el método onResourceReady de SingleRequest.

22,Solicitud única#enRecursoListo

/**
 * 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();
}

En el método SingleRequest#onResourceReady, se llama al método target.onResourceReady(result, animation). El objetivo aquí es en realidad el BitmapImageViewTarget que establecimos en el método into. Al ver la clase BitmapImageViewTarget, no encontramos el método onResourceReady, pero aprendimos from it El método onResourceReady se encuentra en la subclase de ImageViewTarget, desde aquí seguimos mirando hacia abajo.

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

Aquí volvemos al método setResource de BitmapImageViewTarget, y finalmente vemos que el mapa de bits está configurado en la vista de imagen actual.

public class BitmapImageViewTarget extends ImageViewTarget<Bitmap> {
    
    

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

En este punto, nuestro análisis ha terminado. Del análisis anterior, podemos ver que Glide pone la mayor parte del procesamiento lógico en el último método, lo que requiere más de 20 pasos de análisis para procesar el flujo de imágenes solicitado y decodificar la imagen. y finalmente establecer en el imageView correspondiente.

Finalmente, aquí hay un diagrama de flujo completo de carga de Glide que pasé varias horas dibujando. Es muy valioso. Puede ordenar cuidadosamente el proceso principal de Glide nuevamente.

V. Resumen

En este punto, el análisis de todo el proceso de carga de Glide ha terminado. Se puede ver que la lógica central de Glide se reúne en el método into(). El diseño en su interior es exquisito y complejo. El análisis del código fuente de esta parte es consume mucho tiempo Sin embargo, si realmente profundizas paso a paso, es posible que tengas una epifanía en el camino hacia el avance de Android. En la actualidad, la serie de análisis de código fuente de la biblioteca tripartita principal de Android ha llevado a cabo un análisis detallado del código fuente en la biblioteca de red (OkHttp, Retrofit) y la biblioteca de carga de imágenes (Glide). código fuente del marco de la base de datos GreenDao. Espérelo con ansias ~

Link de referencia:

1. Código fuente de Glide V4.8.0

2. Comprender el proceso de ejecución de Glide desde la perspectiva del código fuente

3. Análisis de código fuente deslizante

Reimpresión: https://juejin.cn/post/6844904049595121672

Supongo que te gusta

Origin blog.csdn.net/gqg_guan/article/details/129123271#comments_27548947
Recomendado
Clasificación