Glide源码分析

2020-02-09  本文已影响0人  西瓜家族

它支持拉取、解码、展示,视频快照、图片和GIF动画。提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。Glide 使用简明的流式(链式)语法API,这是一个非常棒的设计,因为它允许你在大部分情况下一行代码搞定需求,因此搞懂这条链式调用的代码都做了什么准备工作,Glide图片加载的大概框架也就明白了许多。

 Glide.with(context)
        .load("")
        .into(imageView);

一、with()方法

概述:with()通过RequestManagerRetriever的单例,静态get方法拿到其对象实例,然后通过成员函数get方法,通过getApplicationManager(Context)方法最终拿到了RequestManager对象实例

public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

RequestManagerRetriever.class

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

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) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }

    return getApplicationManager(context);
  }

public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
        return get(activity.getApplicationContext());
    } else {
        assertNotDestroyed(activity);
        FragmentManager fm = activity.getSupportFragmentManager();
        return supportFragmentGet(activity, fm, null /*parentHint*/);
    }
}
  
 public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(activity, fm, null /*parentHint*/);
    }
  }  

 /** 
  * 通过 get((FragmentActivity) context);和get((Activity) context);
  * 真正获取RequestManager在supportFragmentGet(),fragmentGet()两个方法
  * 两个方法功能一致
  */
 private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
      @Nullable Fragment parentHint) {
    // 创建一个隐藏fragment用于管理Glide加载生命周期  
    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 =
          // 创建RequestManager
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      // 将requestManager保存在创建的fragment中,用于生命周期管理          
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

通过上面源码可以发现get方法其实分为两种,即application类型和非application类型的参数。如果是application类型参数,会调用getApplicationManager(Context),最后返回一个RequestManager对象实例;如果是非application类型参数,最后都会向当前的Activity添加一个隐藏的Fragment。

Glige需要拿到加载的生命周期,当我们在Activity加载一张图片,图片还没有加载,Activity就被销毁了,那图片就不用加载。把Glide放到Fragment中,当Activity销毁,Fragment是可以监听到的,这样就可以实现需求了

二、load()方法

  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) {
      // 创建一个RequestBuilder实例
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }
  public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
  }
  
  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }

三、into()方法

概述:1.初始化各种参数,做好准备工作(网络请求、基于MVP的各种接口回调),2.使用最原始的HTTPConnect网络连接,读取文件流,3.根据文件判断是GIF动图还是Bitmap静态图片,4.通过相关复杂逻辑将下载的图片资源取出来,赋值给ImageView控件

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()) {
        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.
      }
    }
    /**
     * 重点glideContext是在Glide构造方法中创建的,GlideContext类是一个全局的
     * 为所有在Glide中加载任务保存和提供各种registries和classes类
     * 就是一个类似工具类的存在
     * transcodeClass:这里我们传入的是Drawable(在RequestManager中的as()方法传入)
     */
    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions);
  }

跟踪glideContext.buildImageViewTarget()进入ImageViewTargetFactory中
ImageViewTargetFactory工厂类根据不同clazz参数来构建Target对象,clazz参数有两种情况:
1、使用Glide加载图片的时候调用了asBitmap()方法,这里就会构建BitmapImageViewTarget对象。
2、默认都是生成了DrawableImageViewTarget对象。

 public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
      @NonNull Class<Z> clazz) {
    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)");
    }
  }

ViewTarget创建后我们来进入上面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();
    //***重点,用来发出加载图片请求的,它是Glide中非常关键的一个组件***
    Request request = buildRequest(target, targetListener, options);

    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      request.recycle();
      // If the request is completed, beginning again will ensure the result is re-delivered,
      // triggering RequestListeners and Targets. If the request is failed, beginning again will
      // restart the request, giving it another chance to complete. If the request is already
      // running, we can let it continue running without interruption.
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        // Use the previous request rather than the new one to allow for optimizations like skipping
        // setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
        // that are done in the individual Request.
        previous.begin();
      }
      return target;
    }

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

    return target;
  }

接着跟踪buildRequest(target, targetListener, options)方法进入:

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;
    // 这里如果调用了RequestBuilder error()将会进行错误处理
    if (errorBuilder != null) {
      errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }
    
    // 重点
    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions);

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

    int errorOverrideWidth = errorBuilder.requestOptions.getOverrideWidth();
    int errorOverrideHeight = errorBuilder.requestOptions.getOverrideHeight();
    if (Util.isValidDimensions(overrideWidth, overrideHeight)
        && !errorBuilder.requestOptions.isValidOverride()) {
      errorOverrideWidth = requestOptions.getOverrideWidth();
      errorOverrideHeight = requestOptions.getOverrideHeight();
    }

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

继续跟踪:

private Request buildThumbnailRequestRecursive(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) {
        .......
        // 省略缩略图的出来代码
        .......
      // 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) {
    return SingleRequest.obtain(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListener,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory());
  }

随后我们进入SingleRequest.obtain()方法这个方法真正生成一个request:SingleRequest实例
创建好Request实例,我们回到into()方法中,接着:

Request request = buildRequest(target, targetListener, options);
Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      request.recycle();
      // If the request is completed, beginning again will ensure the result is re-delivered,
      // triggering RequestListeners and Targets. If the request is failed, beginning again will
      // restart the request, giving it another chance to complete. If the request is already
      // running, we can let it continue running without interruption.
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        // Use the previous request rather than the new one to allow for optimizations like skipping
        // setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
        // that are done in the individual Request.
        previous.begin();
      }
      return target;
    }
    
    requestManager.clear(target);
    target.setRequest(request);
    // 最后调用这个方法
    requestManager.track(target, request);

接着跟踪track()方法跟踪到下面方法中:

  public void runRequest(Request request) {
    // 请求添加到集合中统一管理
    requests.add(request);
    // 先判断Glide当前是不是Paused(暂停)状态
    if (!isPaused) {
      // 执行SingleRequest中的begin()方法
      request.begin();
    } else {
      // 将Request对象添加到待执行队列里面,等暂停状态解除后再执行
      pendingRequests.add(request);
    }
  }

SingleRequest.java

public void begin() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    if (model == null) {
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        width = overrideWidth;
        height = overrideHeight;
      }
      // Only log at more verbose log levels if the user has set a fallback drawable, because
      // fallback Drawables indicate the user expects null models occasionally.
      int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
      // 如果model==null,最终会调用setErrorPlaceholder(),设置错误占位图
      onLoadFailed(new GlideException("Received null model"), logLevel);
      return;
    }

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

    // If we're restarted after we're complete (usually via something like a notifyDataSetChanged
    // that starts an identical request into the same Target or View), we can simply use the
    // resource and size we retrieved the last time around and skip obtaining a new size, starting a
    // new load etc. This does mean that users who want to restart a load because they expect that
    // the view size has changed will need to explicitly clear the View or Target before starting
    // the new load.
    if (status == Status.COMPLETE) {
      onResourceReady(resource, DataSource.MEMORY_CACHE);
      return;
    }

    // Restarts for requests that are neither complete nor running can be treated as new requests
    // and can run again from the beginning.

    // 图片的一个状态赋值
    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      // 手动为图片指定了宽高
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      // 没有指定宽高,getSize()方法内部会根据ImageView控件的layout_width和layout_height值做一系列的计算,来算出图片对应的宽高,总之在计算完之后,最终还是会调用onSizeReady()方法
      target.getSize(this);
    }

    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      // 在图片请求开始之前会先加载占位图,这就是Glide的placeholder()和 error()这两个占位图API底层的实现原理。 
      target.onLoadStarted(getPlaceholderDrawable());
    }
    if (IS_VERBOSE_LOGGABLE) {
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
  }
public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    if (IS_VERBOSE_LOGGABLE) {
      logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
    if (status != Status.WAITING_FOR_SIZE) {
      return;
    }
    // 给图片赋值一个运行状态
    status = Status.RUNNING;

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

    if (IS_VERBOSE_LOGGABLE) {
      logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
    }
    // 真正的去加载图片
    loadStatus = engine.load(
        glideContext,
        model,
        requestOptions.getSignature(),
        this.width,
        this.height,
        requestOptions.getResourceClass(),
        transcodeClass,
        priority,
        requestOptions.getDiskCacheStrategy(),
        requestOptions.getTransformations(),
        requestOptions.isTransformationRequired(),
        requestOptions.isScaleOnlyOrNoTransform(),
        requestOptions.getOptions(),
        requestOptions.isMemoryCacheable(),
        requestOptions.getUseUnlimitedSourceGeneratorsPool(),
        requestOptions.getUseAnimationPool(),
        requestOptions.getOnlyRetrieveFromCache(),
        this);

    // This is a hack that's only useful for testing right now where loads complete synchronously
    // even though under any executor running on any thread but the main thread, the load would
    // have completed asynchronously.
    if (status != Status.RUNNING) {
      loadStatus = null;
    }
    if (IS_VERBOSE_LOGGABLE) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
  }
public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean useAnimationPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb) {
    Util.assertMainThread();
    long startTime = LogTime.getLogTime();

    // key是用来标记每个请求
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);

    // 第一步  从active Resources中获取
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      // 如果存在则回调
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }

    // 第二布  从缓存中获取
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }
    // active Resources和缓存中都没有请求的资源,创建一个EngineJob
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      current.addCallback(cb);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    EngineJob<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.put(key, engineJob);

    // 添加图片资源下载完成后的回调
    engineJob.addCallback(cb);
    // 开始下载任务
    engineJob.start(decodeJob);

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
  }

继续进入engineJob.start()方法:

 public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    // 这里决定用什么线程池来执行,这里我们拿到的是磁盘缓存中diskCacheExecutor
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor(); 
    executor.execute(decodeJob);
  }
  
  boolean willDecodeFromCache() {
    Stage firstStage = getNextStage(Stage.INITIALIZE);
    return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
  }

DecodeJob是一个Runnable,接下来看他的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.
    TraceCompat.beginSection("DecodeJob#run");
    // 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 (Throwable t) {
      ......
    } finally {
      // Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
      // close in all cases anyway.
      if (localFetcher != null) {
        localFetcher.cleanup();
      }
      TraceCompat.endSection();
    }
  }

  private void runWrapped() {
     switch (runReason) {
      case INITIALIZE:
        // stage 是一个状态标记,标记从哪里decode数据
        // 请求开始是这个状态,所以第一次从这里开始
        stage = getNextStage(Stage.INITIALIZE);
        // 第一次拿到的是ResourceCacheGenerator
        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:
        // 第一次执行这里,默认的disk缓存策略是AUTOMATIC,所以状态切换成RESOURCE_CACHE
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE:
        // 第二次执行到这里,默认AUTOMATIC策略decodeCachedData()返回true
        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:
        // ResourceCache,加载本地Uri资源图片后的缓存
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
        // DataCache 图片disk缓存
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
        // 网络加载器
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }
  
   private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      // 关注点1,startNext方法
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

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

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

currentGenerator有三个实现类,分别是ResourceCacheGenerator,DataCacheGenerator,SourceGenerator
图片在进入disk缓存获取的步骤,也就是DecodeJob中run()方法执行的工作:

1. runWrapped()方法中,获取到的stage是Stage.RESOURCE_CACHE,currentGenerator是ResourceCacheGenerator
2. 然后执行runGenerators()方法中的currentGenerator.startNext()方法,这个方法是真正加载的图片地方,如果在ResourceCacheGenerator中没有数据进入while中执行
3. stage变成Stage.DATA_CACHE,currentGenerator是DataCacheGenerator,再次执行循环
4. 执行DataCacheGenerator的startNext()方法,如果还是没有数据,再次进去while中执行
5. 如果用户选择仅从缓存检索资源,则跳过从源加载(getNextStage()方法中注释Skip loading from source if the user opted to only retrieve the resource from cache.)
6. 此时stage是Stage.SOURCE,currentGenerator是SourceGenerator,进入SourceGenerator的startNext()方法.开始网络加载

SourceGenerator的startNext()方法

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

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

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        // //重点开始加载,并且传入回调this
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

请求成功后回调onDataReady()方法

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

DecodeJob的reschedule():

public void reschedule() {
    runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
    // callback是EngineJob
    callback.reschedule(this);
  }

DecodeJob的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);
  }
public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      // 重点,前面已经获取到数据dataToCache不再为null
      cacheData(data);
    }

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

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        // //重点开始加载,并且传入回调this
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

缓存数据

private void cacheData(Object dataToCache) {
    long startTime = LogTime.getLogTime();
    try {
      Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
      DataCacheWriter<Object> writer =
          new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
      originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
      helper.getDiskCache().put(originalKey, writer);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Finished encoding source to cache"
            + ", key: " + originalKey
            + ", data: " + dataToCache
            + ", encoder: " + encoder
            + ", duration: " + LogTime.getElapsedMillis(startTime));
      }
    } finally {
      loadData.fetcher.cleanup();
    }

    sourceCacheGenerator =
        new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
  }

所以在上面的方法中会去执行DataCacheGenerator的startNex()方法,和SourceGenerator类似,随后执行DataCacheGenerator的对应回调方法:

public void onDataReady(Object data) {
    // cb是SourceGenerator
    cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
  }

SourceGenerator

public void onDataReady(Object data) {
    // cb 是DecodeJob
    cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.RESOURCE_DISK_CACHE,
        currentKey);
  }

DecodeJob

public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
      DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;
    this.currentData = data;
    this.currentFetcher = fetcher;
    this.currentDataSource = dataSource;
    this.currentAttemptingKey = attemptedKey;
    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
    } else {
      TraceCompat.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        // decode我们需要的数据
        decodeFromRetrievedData();
      } finally {
        TraceCompat.endSection();
      }
    }
  }
  
  
  private void decodeFromRetrievedData() {
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logWithTimeAndKey("Retrieved data", startFetchTime,
          "data: " + currentData
          + ", cache key: " + currentSourceKey
          + ", fetcher: " + currentFetcher);
    }
    Resource<R> resource = null;
    try {
      // 解析到资源
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }
  
  
  private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
    if (resource instanceof Initializable) {
      ((Initializable) resource).initialize();
    }

    Resource<R> result = resource;
    LockedResource<R> lockedResource = null;
    if (deferredEncodeManager.hasResourceToEncode()) {
      lockedResource = LockedResource.obtain(resource);
      result = lockedResource;
    }

    // 这里数据已经加载出来
    notifyComplete(result, dataSource);

    stage = Stage.ENCODE;
    try {
      if (deferredEncodeManager.hasResourceToEncode()) {
        deferredEncodeManager.encode(diskCacheProvider, options);
      }
    } finally {
      if (lockedResource != null) {
        lockedResource.unlock();
      }
    }
    // Call onEncodeComplete outside the finally block so that it's not called if the encode process
    // throws.
    onEncodeComplete();
  }
  
  
  private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
    
    // callback 是EngineJob
    callback.onResourceReady(resource, dataSource);
  }
  
  
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    this.resource = resource;
    this.dataSource = dataSource;
    // 这里通过主线程handler将当前EngineJob发送到主线程消息队列中
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
  }

主线程handler处理消息,最后执行到handleResultOnMainThread()方法中cb.onResourceReady(engineResource, dataSource);cb的实现是最初的SingleRequest,执行SingleRequest的onResourceReady()方法中的target.onResourceReady(result, animation);这里的target的实现是ImageViewTarget,ImageViewTarget也是一个抽象类

总结

1. Glide.with(Context)获取一个RequestManager对象,这期间,如果Glide实例没有,会创建一个全局的单实例。在创建RequestManager时,会去将RequestManager绑定到一个隐藏的RequestManagerFragment中进行生命周期管理
2. load()方法将确定具体的加载类型保存到一个RequestBuilder中,它也保存着其他RequestOptions
3. into()方法将在RequestBuilder中创建一个SingleRequest实例,随后onSizeReady()方法被调用,engine开始发起请求加载图片
4. Engine图片加载分为三步,第一步先从active Resources中取,active Resources 是那些至少已经被提供给一个request的并且还没有被释放的,第二步从MemoryCache中获取,如果还是没有,第三步将会创建一个新的请求
5. 在Engine的load()中创建一个DecodeJob,Engine将它放入线程池中执行,decodeJob先从ResourceCache中获取,再从DataCache中,最后SourceGenerator的startNext()方法中发起网络请求.网络加载完成后先缓存下来,DecodeJob再次运行,在DataCacheGenerator的startNext()中获取到数据,经过层层回调在DecodeJob的decodeFromRetrievedData()方法中将resource解析出来,最后回调到EngineJob的onResourceReady()方法,通过主线程Handler完成线程切换并将当前EngineJob通过Message发送到主线程的消息队列,随后处理,接着回调到SingRequest的onResourceReady()方法,随后回调target的onResourceReady()方法,到这里图片加载到对应的target,完成.

补充:Glide缓存机制

Glide的缓存分为两种,Resource缓存、Bitmap缓存。

一、Resource缓存:

首先Resource缓存就是缓存整体的图片资源文件,缓存它是为了当首次从服务器端下载下来之后,缓存到本地,如果再次使用这个图片,不用去跑网络请求,直接从本地读取,节省流量也提高访问速度。它使用的是三级缓存原理:

一级缓存:内存缓存,缓存被回收的资源,使用LRU算法(Least Frequently Used,最近最少使用算法),当需要再次使用到被回收的资源时,直接从内存中读取;
二级缓存:使用弱引用缓存正在使用的资源,当系统执行GC操作时,会回收没有强引用的资源。使用弱引用缓存,既可以缓存当前正在强引用使用的资源,又不阻碍系统回收无引用的资源
三级缓存:磁盘缓存,网络图片下载成功后,以文件的形式缓存到磁盘中
1和2都是内存缓存,只不过功能不一样,1是使用LRU算法缓存被GC回收的资源,2是用弱引用缓存正在使用的资源。在复用图片资源的时候首先从回收的内存缓存集合中查找,内存缓存的集合中没有的时候,去弱引用集合查找是否是当前正在使用,没有的话,去磁盘中查找,再没有的时候去网络中查找。

二、Bitmap缓存:

Bitmap所占的内存大小由其三部分组成:图片宽,高和Bitmap质量参数

bitmap内存大小 = 宽*高*质量参数所占的位数,单位是字节b

ALPHA—8就是Alpha是由8位组成的(1B)
ARGB_4444,4个4位组成16位(2B)
ARGB_8888,4个8位组成32位(4B)
RGB_565,R是5位,G是6位,B是5位组成16位(2B),Glide默认bitmap压缩参数就是这个RGB_565,但是它不能显示透明度
先说一下为什么要进行bitmap压缩,比如在recycleView中加载大量的图片,频繁的创建和回收Bitmap会导致内存波动影响性能,既然这样,我们能不能缓存Bitmap,不要让它老是new和销毁,这应该是Glide去做Bitmap缓存的原因,

Bitmap缓存算法:在Glide中使用BitmapPool来缓存Bitmap,使用的也是LRU算法(最近最少使用算法),当需要使用Bitmap时,先从Bitmap的池子中选取,如果找不到合适的Bitmap,再去创建,当使用完毕后,不再直接调用Bitmap.recycle()释放内存,而是缓存到Bitmap池子里。

Bitmap的缓存是以键值对的方式进行缓存的,Resource和Bitmap都作为Value,而这些值是需要一个key来标识缓存的内容,根据key可以查找和移除对应的缓存。

上一篇下一篇

猜你喜欢

热点阅读