美文网首页
Glide流程解析

Glide流程解析

作者: 蜗牛是不是牛 | 来源:发表于2022-04-07 21:14 被阅读0次

Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。

从主流程分析

Glide最简单的使用:

Glide
    .with(context)
    .load("https://github.com/bumptech/glide/blob/master/static/glide_logo.png")
    .into(iv)

Glide加载图片最简单的是三步:

  • Glide.with(context)来获取Glide对象和RequestManager对象并绑定Context生命周期;
  • RequestManager.load(url)获取RequestBuilder对象并绑定图片Url,此时还没有去加载Url地址;
  • RequestBuilder.into(iv)加载图片并且将获取到的图片显示到ImageView中。

下面跟着三步一步一步来看下具体实现。

Glide.with(context)

com.bumptech.glide.Glide#with(Context)

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

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
  return Glide.get(context).getRequestManagerRetriever();
}

// 获取Glide单例对象
public static Glide get(@NonNull Context context) {
  if (glide == null) {
    GeneratedAppGlideModule annotationGeneratedModule =
        getAnnotationGeneratedGlideModules(context.getApplicationContext());
    synchronized (Glide.class) {
      if (glide == null) {
        checkAndInitializeGlide(context, annotationGeneratedModule);
      }
    }
  }
  return glide;
}

Glide.with()一共有两大步:

  • getRetriever(context)获取Glide单例对象和RequestManagerRetriever对象;
  • get(context)获取RequestManager对象同时绑定当前Context的生命周期。

Glide单例创建

Glide对象的首次创建跟代码是从Glide.get(context)->checkAndInitializeGlide()->initializeGlide()->GlideBuilder#build(),最终通过建造者模式创建Glide对象。

com.bumptech.glide.GlideBuilder#build

Glide build(@NonNull Context context) {
  if (sourceExecutor == null) {
    sourceExecutor = GlideExecutor.newSourceExecutor();
  }

  if (diskCacheExecutor == null) {
    diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
  }

  if (animationExecutor == null) {
    animationExecutor = GlideExecutor.newAnimationExecutor();
  }

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

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

  if (bitmapPool == null) {
    int size = memorySizeCalculator.getBitmapPoolSize();
    if (size > 0) {
      bitmapPool = new LruBitmapPool(size);
    } else {
      bitmapPool = new BitmapPoolAdapter();
    }
  }

  if (arrayPool == null) {
    arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
  }

  if (memoryCache == null) {
    memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
  }

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

  if (engine == null) {
    engine =
        new Engine(
            memoryCache,
            diskCacheFactory,
            diskCacheExecutor,
            sourceExecutor,
            GlideExecutor.newUnlimitedSourceExecutor(),
            animationExecutor,
            isActiveResourceRetentionAllowed);
  }

  if (defaultRequestListeners == null) {
    defaultRequestListeners = Collections.emptyList();
  } else {
    defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
  }

  GlideExperiments experiments = glideExperimentsBuilder.build();
  RequestManagerRetriever requestManagerRetriever =
      new RequestManagerRetriever(requestManagerFactory, experiments);

  return new Glide(
      context,
      engine,
      memoryCache,
      bitmapPool,
      arrayPool,
      requestManagerRetriever,
      connectivityMonitorFactory,
      logLevel,
      defaultRequestOptionsFactory,
      defaultTransitionOptions,
      defaultRequestListeners,
      experiments);
}

创建Glide对象的同时还创建其它很多的实例,包括缓存执行器SourceExecutorDiskCacheExecutor,加载引擎EngineRequestManagerRetriever等。

RequestManager创建

com.bumptech.glide.manager.RequestManagerRetriever#get(Context)

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)) {
    if (context instanceof FragmentActivity) {
      return get((FragmentActivity) context);
    } else if (context instanceof Activity) {
      return get((Activity) context);
    } else if (context instanceof ContextWrapper
        // Only unwrap a ContextWrapper if the baseContext has a non-null application context.
        // Context#createPackageContext may return a Context without an Application instance,
        // in which case a ContextWrapper may be used to attach one.
        && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
      return get(((ContextWrapper) context).getBaseContext());
    }
  }

  return getApplicationManager(context);
}

这里做了很多Context类型的区分,只要就是得到不同的生命周期类型:

  • 在主线程并且不是Application,判断下是FragmentActivity还是Activity,都不是获取BaseContext重新进来判断一遍;
  • 其余都作为Application来绑定生命周期。

我们选择FragmentActivity分支来继续往下追:

@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
  if (Util.isOnBackgroundThread()) {
    return get(activity.getApplicationContext());
  } else {
    assertNotDestroyed(activity);
    frameWaiter.registerSelf(activity);
    FragmentManager fm = activity.getSupportFragmentManager(); ①
    return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
  }
}

  @NonNull
private RequestManager supportFragmentGet(
    @NonNull Context context,
    @NonNull FragmentManager fm,
    @Nullable Fragment parentHint,
    boolean isParentVisible) {
  SupportRequestManagerFragment current = 
    getSupportRequestManagerFragment(fm, parentHint); ②
  RequestManager requestManager = current.getRequestManager(); ③
  if (requestManager == null) {
    // TODO(b/27524013): Factor out this Glide.get() call.
    Glide glide = Glide.get(context);
    requestManager =
        factory.build(
            glide, current.getGlideLifecycle(), 
            current.getRequestManagerTreeNode(), context); ④
    if (isParentVisible) {
      requestManager.onStart();
    }
    current.setRequestManager(requestManager); ⑤
  }
  return requestManager;
}

  • 第一步获取Activity对应的FragmentManager
  • 第二步根据FragmentManager获取对应Fragment,如果没有创建一个新的SupportRequestManagerFragment对象,并且放入到Map中;如果已经存在,直接从Map中获取;
  • 第三步,从Fragment中获取RequestManager对象;
  • 第四步,如果没有获取到,就重新创建一个新的对象,第五步就是将新的RequestManagerFragment绑定。

这里的SupportRequestManagerFragment其实就是一个空布局的Fragment,主要作用是感知Activity的生命周期。

RequestManager.load(url)

com.bumptech.glide.RequestManager#load(java.lang.String)

public RequestBuilder<Drawable> load(@Nullable String string) {
  return asDrawable().load(string);
}

public RequestBuilder<Drawable> asDrawable() {
  return as(Drawable.class);
}
  
public <ResourceType> RequestBuilder<ResourceType> as(
  @NonNull Class<ResourceType> resourceClass) {
  return new RequestBuilder<>(glide, this, resourceClass, context);
}
    
public RequestBuilder<TranscodeType> load(@Nullable String string) {
  return loadGeneric(string);
}
      
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
  if (isAutoCloneEnabled()) {
    return clone().loadGeneric(model);
  }
  this.model = model;
  isModelSet = true;
  return selfOrThrowIfLocked();
}

这个流程逻辑相对比较少的,主要就是创建了一个RequestBuilder对象,并且它的泛型参数是Drawable类型,因为我们分析的是加载Url到指定的ImageView

RequestBuilder.into(iv)

com.bumptech.glide.RequestBuilder#into(ImageView)

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
  Util.assertMainThread();
  Preconditions.checkNotNull(view);
  BaseRequestOptions<?> requestOptions = this;
  if (!requestOptions.isTransformationSet()
      && requestOptions.isTransformationAllowed()
      && view.getScaleType() != null) {
    switch (view.getScaleType()) { ①
      case CENTER_CROP:
        requestOptions = requestOptions.clone().optionalCenterCrop();
        break;
        ..... 省略其它缩放类型
    }
  }

  return into(
      glideContext.buildImageViewTarget(view, transcodeClass),
      /*targetListener=*/ null,
      requestOptions,
      Executors.mainThreadExecutor()); ②
}

  • 第一处查看ImageView是否设置了缩放类型,如果有添加类型至RequestOptions中;

  • 进入into()方法中具体执行,这里传了四个参数:

    • 第一个ImageView目标,包含了资源类型就是Drawable.class
    • 第二个是请求监听RequestListener,包括了加载失败和资源准备完成两个回调,这里传的是空值;
    • 第三个是请求的选项RequestOptions
    • 第四个是回调的线程池,这边最终回调到主线程。

into(target,reqeuestListener,options,callbackExecutor)

com.bumptech.glide.RequestBuilder#into

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

  Request request = buildRequest(target, targetListener, options, callbackExecutor); ①

  Request previous = target.getRequest(); ②
  if (request.isEquivalentTo(previous)
      && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { ③
    if (!Preconditions.checkNotNull(previous).isRunning()) {
      previous.begin();
    }
    return target;
  }

  requestManager.clear(target);
  target.setRequest(request);
  requestManager.track(target, request); ④

  return target;
}

  • 第一步,构建一个Request对象,这个下面着重介绍下;

  • 第二步从Target对象里面获取已存在的请求;

  • 第三步判断是否可以复用已存在的请求:

    • 第一个条件是requestprevious是否参数一致,请求类型一致;
    • 是否设置了跳过缓存并且previous已经完成。
  • 第四步如果不能复用,那么就使用构建的Request对象,最后调用RequestManager.track(target,request) 方法。

接着我们先暂停主流程,进入构建Request对象的逻辑里面。

buildRequest(target,targetListener,opstions,callbackExecutor)

com.bumptech.glide.RequestBuilder#buildRequest  

private Request buildRequest(
    Target<TranscodeType> target,
    @Nullable RequestListener<TranscodeType> targetListener,
    BaseRequestOptions<?> requestOptions,
    Executor callbackExecutor) {
  return buildRequestRecursive(
      /*requestLock=*/ new Object(),
      target,
      targetListener,
      /*parentCoordinator=*/ null,
      transitionOptions,
      requestOptions.getPriority(),
      requestOptions.getOverrideWidth(),
      requestOptions.getOverrideHeight(),
      requestOptions,
      callbackExecutor);
}

这里直接调用buildRequestRecursive()方法。

com.bumptech.glide.RequestBuilder#buildRequestRecursive

private Request buildRequestRecursive(
    Object requestLock,
    Target<TranscodeType> target,
    @Nullable RequestListener<TranscodeType> targetListener,
    @Nullable RequestCoordinator parentCoordinator,
    TransitionOptions<?, ? super TranscodeType> transitionOptions,
    Priority priority,
    int overrideWidth,
    int overrideHeight,
    BaseRequestOptions<?> requestOptions,
    Executor callbackExecutor) {
    
    // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
    ErrorRequestCoordinator errorRequestCoordinator = null; 
    if (errorBuilder != null) { ①
        errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
        parentCoordinator = errorRequestCoordinator;
    }
    
    Request mainRequest =
    buildThumbnailRequestRecursive(
        requestLock,
        target,
        targetListener,
        parentCoordinator,
        transitionOptions,
        priority,
        overrideWidth,
        overrideHeight,
        requestOptions,
        callbackExecutor); ②
    
    if (errorRequestCoordinator == null) { ③
        return mainRequest;
    }
    
    int errorOverrideWidth = errorBuilder.getOverrideWidth();
    int errorOverrideHeight = errorBuilder.getOverrideHeight();
    if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.isValidOverride()) {
        errorOverrideWidth = requestOptions.getOverrideWidth();
        errorOverrideHeight = requestOptions.getOverrideHeight();
    }
    
    Request errorRequest =
    errorBuilder.buildRequestRecursive(
        requestLock,
        target,
        targetListener,
        errorRequestCoordinator,
        errorBuilder.transitionOptions,
        errorBuilder.getPriority(),
        errorOverrideWidth,
        errorOverrideHeight,
        errorBuilder,
        callbackExecutor);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest); ④
    return errorRequestCoordinator;
}

  • 第一步,判断errorBuilder是否为空,这个errorBuilder是我们通过RequestBuilder.error()设置的,如果不为空,将会生成一个协调器ErrorRequestCoordinator用于协调下面mainRequesterrorRequest,现在我们默认未设置,只看主流程;
  • 第二步通过buildThumbnailRequestRecursive()生成mainRequest
  • 第三步如果errorRequestCoordinator为空直接返回mainRequest
  • 第四步如果errorRequestCoordinator不为空还将生成一个errorRequest

接着主流程我们看看mainRequest是怎么生成的。

buildThumbnailRequestRecursive()

com.bumptech.glide.RequestBuilder#buildThumbnailRequestRecursive

private Request buildThumbnailRequestRecursive(
      Object requestLock,
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      BaseRequestOptions<?> requestOptions,
      Executor callbackExecutor) {
    if (thumbnailBuilder != null) {
      // Recursive case: contains a potentially recursive thumbnail request builder.
      if (isThumbnailBuilt) {
        throw new IllegalStateException(
            "You cannot use a request as both the main request and a "
                + "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
      }

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

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

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

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

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

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

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

这边我们先忽略缩略图的设置,直接看最后else分支中,直接返回的是obtainRequest()方法的返回值。

com.bumptech.glide.RequestBuilder#obtainRequest

private Request obtainRequest(
    Object requestLock,
    Target<TranscodeType> target,
    RequestListener<TranscodeType> targetListener,
    BaseRequestOptions<?> requestOptions,
    RequestCoordinator requestCoordinator,
    TransitionOptions<?, ? super TranscodeType> transitionOptions,
    Priority priority,
    int overrideWidth,
    int overrideHeight,
    Executor callbackExecutor) {
  return SingleRequest.obtain(
      context,
      glideContext,
      requestLock,
      model,
      transcodeClass,
      requestOptions,
      overrideWidth,
      overrideHeight,
      priority,
      target,
      targetListener,
      requestListeners,
      requestCoordinator,
      glideContext.getEngine(),
      transitionOptions.getTransitionFactory(),
      callbackExecutor);
}

到这里停止,我们最终可以看到其实经过很多层最后得到的是SingleRequest对象。接着我们需要跳回到into()方法中的最后一行代码RequestManager.track(target,request),这里面的request就是我们刚刚看到的SingleRequest对象。

RequestManager.track(target,request)

com.bumptech.glide.RequestManager#track

synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
  targetTracker.track(target); ①
  requestTracker.runRequest(request); ②
}

com.bumptech.glide.manager.TargetTracker#track
private final Set<Target<?>> targets =
    Collections.newSetFromMap(new WeakHashMap<Target<?>, Boolean>());

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

com.bumptech.glide.manager.RequestTracker#runRequest
private final Set<Request> requests =
    Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
private final Set<Request> pendingRequests = new HashSet<>();

public void runRequest(@NonNull Request request) {
  requests.add(request);
  if (!isPaused) {
    request.begin();
  } else {
    request.clear();
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      Log.v(TAG, "Paused, delaying request");
    }
    pendingRequests.add(request);
  }
}

这个方法是加了synchronized为了线程安全,一共作了两个操作:

  • 第一步将target添加到TargetTracker.targets集合中;
  • 第二步运行SingleRequest,首先将SingleRequest添加到RequestTracker.requests集合中,如果当前不是暂停状态,直接调用SingleRequest.begin()方法,如果当前是暂停状态,那么就将SingleRequest添加到待定的集合中pendingRequests

我们继续往下看,进入SingleRequest.begin()方法。

SingleRequest.begin()

com.bumptech.glide.request.SingleRequest#begin

public void begin() {
  synchronized (requestLock) {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    if (model == null) { ①
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        width = overrideWidth;
        height = overrideHeight;
      }
      int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
      onLoadFailed(new GlideException("Received null model"), logLevel);
      return;
    }

    if (status == Status.RUNNING) { ②
      throw new IllegalArgumentException("Cannot restart a running request");
    }
    if (status == Status.COMPLETE) { ③
      onResourceReady(
          resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
      return;
    }
    experimentalNotifyRequestStarted(model);

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

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

整个begin()方法中,我么分为了5步来梳理:

  • 第一步model也就是url如果为空,直接返回,回调onLoadFailed()
  • 第二步判断当前状态如果是RUNNING状态,直接抛异常,一个Request只能同时执行一次;
  • 第三步判断当前状态如果是COMMPLETE状态,那么可以直接返回resourceonResourceReady()后续会将获取到的Drawable显示到指定的ImageView中,这个后面会有解析;
  • 第四步判断宽高是否有效,如果有效直接进入onSizeReady()方法,开启加载模式,此时状态会进入RUNNING状态
  • 第五步如果当前状态为RUNNING或者WAITING_FOR_SIZE状态,显示占位图。

SingleRequest.onSizeReady(width,height)

com.bumptech.glide.request.SingleRequest#onSizeReady  

public void onSizeReady(int width, int height) {
  stateVerifier.throwIfRecycled();
  synchronized (requestLock) {
    if (status != Status.WAITING_FOR_SIZE) {
      return;
    }
    status = Status.RUNNING; ①

    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
    loadStatus =
        engine.load(
            glideContext,
            model,
            requestOptions.getSignature(),
            this.width,
            this.height,
            requestOptions.getResourceClass(),
            transcodeClass,
            priority,
            requestOptions.getDiskCacheStrategy(),
            requestOptions.getTransformations(),
            requestOptions.isTransformationRequired(),
            requestOptions.isScaleOnlyOrNoTransform(),
            requestOptions.getOptions(),
            requestOptions.isMemoryCacheable(),
            requestOptions.getUseUnlimitedSourceGeneratorsPool(),
            requestOptions.getUseAnimationPool(),
            requestOptions.getOnlyRetrieveFromCache(),
            this,
            callbackExecutor); ②
  }
}

  • 第一步先将状态设置为RUNNING
  • 启动Engine引擎去加载图片。

Engine.load()

com.bumptech.glide.load.engine.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,
      Executor callbackExecutor) {
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

    EngineKey key =
        keyFactory.buildKey(
            model,
            signature,
            width,
            height,
            transformations,
            resourceClass,
            transcodeClass,
            options); ①

    EngineResource<?> memoryResource;
    synchronized (this) {
      memoryResource = loadFromMemory(key, isMemoryCacheable, startTime); ②

      if (memoryResource == null) {
        return waitForExistingOrStartNewJob(
            glideContext,
            model,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            options,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache,
            cb,
            callbackExecutor,
            key,
            startTime); ③
      }
    }

    // Avoid calling back while holding the engine lock, doing so makes it easier for callers to
    // deadlock.
    cb.onResourceReady(
        memoryResource, DataSource.MEMORY_CACHE, false); ④
    return null;
  }

  • 第一步生成EngineKey,用作后续写缓存或者读缓存使用;
  • 第二步去缓存中寻找,先从活动缓存ActivityResource,再去内存缓存中MemoryCache中;
  • 第三步如果内存缓存中没有命中,那么开始新的任务

Engine.waitForExistingOrStartNewJob()

com.bumptech.glide.load.engine.Engine#waitForExistingOrStartNewJob

private <R> LoadStatus waitForExistingOrStartNewJob(...) {
    // 从Jobs map中查找,已经存在就直接返回
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); ①
    if (current != null) {
      current.addCallback(cb, callbackExecutor);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }
    // 创建EngineJob
    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache); ②
    // 创建解码器DecodeJob,
    // 注意最后一次参数,传的是EngineJob,因为EngineJob实现了DecodeJob.Callback
    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob); ③
    // 存到Jobs map中
    jobs.put(key, engineJob);
    // 将EngineJob和callback,callbackExecutor绑定
    // cb是回调资源是否加载完成,callbackExecutor是回调到主线程
    engineJob.addCallback(cb, callbackExecutor);
    // 调用EngineJob.start()其实就是调用线程池执行Runnable,而decodeJob就是实现了Runnable
    engineJob.start(decodeJob); ④

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

  • 第一步查找是否已经存在此Job,若已存在直接返回;
  • 第二步创建EngineJob对象,用于开启任务,回调资源加载成功和失败;
  • 第三步创建DecodeJob对象,用于加载资源,操作缓存等,并且此时DecodeJob已经和EngineJobCallback形式绑定在一起;
  • 第四步开始执行DecodeJobrun()方法,EngineJob.start()内部就是调用线程池的excute()方法,传入的正是DecodeJob,所以我们进入DecodeJob.run()方法继续分析。

DecodeJob.run()

com.bumptech.glide.load.engine.DecodeJob#run 

public void run() {
  // This should be much more fine grained, but since Java's thread pool implementation silently
  // swallows all otherwise fatal exceptions, this will at least make it obvious to developers
  // that something is failing.
  GlideTrace.beginSectionFormat("DecodeJob#run(reason=%s, model=%s)", runReason, model);
  // Methods in the try statement can invalidate currentFetcher, so set a local variable here to
  // ensure that the fetcher is cleaned up either way.
  DataFetcher<?> localFetcher = currentFetcher;
  try {
    // 如果被取消了,直接回调失败
    if (isCancelled) {
      notifyFailed();
      return;
    }
    // 下一步逻辑
    runWrapped(); ①
  } catch (CallbackException e) {
    throw e;
  } finally {
    if (localFetcher != null) {
      // 回收资源,Http Stream、File Stream等
      localFetcher.cleanup();
    }
    GlideTrace.endSection();
  }
}

run()方法内部直接进入runWrapped()方法。

DecodeJob#runWrapped

com.bumptech.glide.load.engine.DecodeJob#runWrapped

private void runWrapped() {
  switch (runReason) {
    case INITIALIZE:
      stage = getNextStage(Stage.INITIALIZE);
      currentGenerator = getNextGenerator();
      runGenerators();
      break;
    case SWITCH_TO_SOURCE_SERVICE:
      runGenerators();
      break;
    case DECODE_DATA:
      decodeFromRetrievedData();
      break;
    default:
      throw new IllegalStateException("Unrecognized run reason: " + runReason);
  }
}

private Stage getNextStage(Stage current) {
  switch (current) {
    case INITIALIZE:
      return diskCacheStrategy.decodeCachedResource()
          ? Stage.RESOURCE_CACHE
          : getNextStage(Stage.RESOURCE_CACHE);
    case RESOURCE_CACHE:
      return diskCacheStrategy.decodeCachedData()
          ? Stage.DATA_CACHE
          : getNextStage(Stage.DATA_CACHE);
    case DATA_CACHE:
      // Skip loading from source if the user opted to only retrieve the resource from cache.
      return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
    case SOURCE:
    case FINISHED:
      return Stage.FINISHED;
    default:
      throw new IllegalArgumentException("Unrecognized stage: " + current);
  }
}

private DataFetcherGenerator getNextGenerator() {
  switch (stage) {
    case RESOURCE_CACHE:
      return new ResourceCacheGenerator(decodeHelper, this);
    case DATA_CACHE:
      return new DataCacheGenerator(decodeHelper, this);
    case SOURCE:
      return new SourceGenerator(decodeHelper, this);
    case FINISHED:
      return null;
    default:
      throw new IllegalStateException("Unrecognized stage: " + stage);
  }
}

private enum RunReason {
  /** 首次提交任务 */
  INITIALIZE,
  /** 尝试从磁盘缓存切到内存缓存 */
  SWITCH_TO_SOURCE_SERVICE,
  /**
   * 解码原数据,也就是去加载资源
   */
  DECODE_DATA,
}

先看下RunReason这个枚举类,一共有三个状态:

  • INITIALIZE:代表首次提交任务;
  • SWITCH_TO_SOURCE_SERVICE:磁盘缓存中有,切到内存缓存中;
  • DECODE_DATA:直接去加载资源(未命中缓存)。

然后我们再看runWrapped()方法,runReason变量在init()方法中赋值为INITIALIZE状态。这样我们先从第一个case查看:默认缓存全开

  • 首先通过getNextStage(Stage.INITIALIZE)获取下一个阶段,默认缓存全开,下一状态为Stage.RESOURCE_CACHE
  • 然后通过getNextGenerator()获取到下一个DataFetcherGenerator,由于上面StageRESOURCE_CACHE,所以返回的是ResourceCacheGenerator,这个Generator就是从磁盘缓存中获取是否有经过编解码、转码之后的缓存;
  • 最后调用runGenerators()

DecodeJob#runGenerators

com.bumptech.glide.load.engine.DecodeJob#runGenerators

private void runGenerators() {
  currentThread = Thread.currentThread();
  startFetchTime = LogTime.getLogTime();
  boolean isStarted = false;
  // while循环,知道stage==SOURCE,才结束
  while (!isCancelled
      && currentGenerator != null
      && !(isStarted = currentGenerator.startNext())) {
    stage = getNextStage(stage);
    currentGenerator = getNextGenerator();

    if (stage == Stage.SOURCE) {
      reschedule();
      return;
    }
  }
  // We've run out of stages and generators, give up.
  if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
    notifyFailed();
  }
}

这里我们可以看到,进入while循环,其中currentGenerator.startNext()是获取ResourceCacheGenerator是否已存在缓存,如果存在那么就直接返回了,不存在继续往下走,直到stage=Stage.Source,然后调用reschedule()方法。

DecodeJob#reschedule

com.bumptech.glide.load.engine.DecodeJob#reschedule

public void reschedule() {
  // 首先将runReason置为SWITCH_TO_SOURCE_SERVICE
  runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
  // 然后调用callback.reschedule(this)
  callback.reschedule(this);
}

  • 第一步改变runReason值,置为SWITCH_TO_SOURCE_SERVICE
  • 第二步调用callback.reschedule()方法,前面创建DecodeJob对象的时候提过,这里的callback就是EngineJob对象,所以我们又得回到EngineJob.reschedule()方法。

EngineJob#reschedule

com.bumptech.glide.load.engine.EngineJob#reschedule

public void reschedule(DecodeJob<?> job) {
  // Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself
  // up.
  getActiveSourceExecutor().execute(job);
}

这里拿到sourceExecutor的线程池,再去执行DecodeJob.run()方法...有点头晕

但是几个状态我们需要知道,对于DecodeJob,它的runReason已经是SWITCH_TO_SOURCE_SERVICE并且stageSOURCE了。

到这之后又会回到DecodeJob.run()方法,然后去DataSourceGenerator去查找是否有源文件缓存,如果有直接返回,没有就去SourceGenerator去加载资源。

总结加载流程:

  • 先从ResourceCacheGenerator中去寻找是否有经过转换、解码之后的磁盘文件缓存,这个缓存要比源文件缓存小;
  • 再从DataSourceGenerator中寻找源文件磁盘缓存,这个是加载的源文件直接写入缓存;
  • 如果都没命中,那么就去Http请求资源,资源请求回来之后先写入磁盘缓存,再返回到Target

最后我们看下资源拿到之后是如何回调到Target,当资源得到之后,会调用onResourceReady()回调方法,此方法的回调链为:SingleRequest#onResourceReady->ImageViewTarget#onResourceReady->mageViewTarget#setResourceInternal->DrawableImageViewTarget#setResource

com.bumptech.glide.request.target.DrawableImageViewTarget#setResource

protected void setResource(@Nullable Drawable resource) {
  view.setImageDrawable(resource);
}

最终在DrawableImageViewTarget中降Resource设置给ImageView

为了大家更便捷的对这源码分析,我将方法引用都放在代码块的最上方,大家可以参考。


Glide源码很多不容易一时间啃完,大家可以多读读多看看,了解下每个对象的工作内容,然后再去反复理解,加载逻辑中涉及到缓存的查找已经资源的加载,理清楚之后就会觉得豁然开朗,加油~

相关文章

网友评论

      本文标题:Glide流程解析

      本文链接:https://www.haomeiwen.com/subject/dnwssrtx.html