Gilde的简单分析

Gilde三大主线

Gilde.with(this).load("url").into(iv_image) 使用来很简单,但是源码却是异常庞大,所以这次只挑一些重点的去看。

  1. with
    with函数是一个静态方法,可以接受Context,Activity,FragmentActivity,Fragment和View的传参。
public static RequestManager with(@NonNull Context context) {
   return getRetriever(context).get(context);
}
public static RequestManager with(@NonNull Activity activity) {
   return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull FragmentActivity activity) {
   return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull Fragment fragment) {
   return getRetriever(fragment.getContext()).get(fragment);
}
public static RequestManager with(@NonNull View view) {
   return getRetriever(view.getContext()).get(view);
}

创建一个RequestManager对象返回,这个对象创建是通过getRetriever获取RequestManagerRetriever对象返回的。看一下RequestManagerRetriever是怎么进行初始化的。

// GlideBuilder.java
 
Glide build(@NonNull Context context) {
      // 分配线程池、配置缓存策略
      sourceExecutor = GlideExecutor.newSourceExecutor();
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
      animationExecutor = GlideExecutor.newAnimationExecutor();
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
      // 监听网络变化
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
      int size = memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) {
        bitmapPool = new LruBitmapPool(size);
      } else {
        bitmapPool = new BitmapPoolAdapter();
      }
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
 
    // engine是负责执行加载任务的
    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);
    }
 
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);
 
    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptionsFactory,
        defaultTransitionOptions,
        defaultRequestListeners,
        isLoggingRequestOriginsEnabled,
        isImageDecoderEnabledForBitmaps);
  }

可以看到Gilde在执行get()方法的是就已经把缓存线程池,资源加载,缓存策略配置好了。网络状态监听。因为get()有很多重载的方法,我们以Context为例,此时RequestManager 绑定了ApplicationContext,所以和app的生命周期一致了,

// RequestManagerRetriever.java
 
// get有好几个重载方法,这里仅选取context参数进行分析
public RequestManager get(@NonNull Context context) {
    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
          && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }
    return getApplicationManager(context);
  }

这里有一个生命周期的管理:

private RequestManager fragmentGet(
   @NonNull Context context,
   @NonNull android.app.FragmentManager fm,
   @Nullable android.app.Fragment parentHint,
   boolean isParentVisible) {
   /**创建了RequestManagerFragment,这是一个空页面*/
 RequestManagerFragment current = getRequestManagerFragment(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);
   // This is a bit of hack, we're going to start the RequestManager, but not the
   // corresponding Lifecycle. It's safe to start the RequestManager, but starting the
   // Lifecycle might trigger memory leaks. See b/154405040
   if (isParentVisible) {
     requestManager.onStart();
   }
   current.setRequestManager(requestManager);
 }
 return requestManager;
}

首先调用了fragemntGet的方法,先创建了一个RequestManagerFragemnt的空页面,用来同步当前页面生命周期,做了一个状态回调,通过setRequestManager塞给了RequestManagerFragment。

执行完with以后我们会得到一个RequestManager对象,接下来就是执行load(url)

  1. Load
    其实Load方法很简单 就是创建了RequestBuilder对象,因为load传入的类型很多,只是将这些需要加载的东西赋值。
    3.into
    into应该gilde中内容最多最复杂的地方了。
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
 Util.assertMainThread();
 Preconditions.checkNotNull(view);

 BaseRequestOptions<?> requestOptions = this;
 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.
   }
 }
 return into(
     glideContext.buildImageViewTarget(view, transcodeClass),
     /*targetListener=*/ null,
     requestOptions,
     Executors.mainThreadExecutor());
}

RequestBuilder的into方法,有三个参数,第一个就是Target对象, 一个是线程池,线程的上下文切换。

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()");
  }
    /**① 创建一个SingleRequest对象 */
  Request request = buildRequest(target, targetListener, options, callbackExecutor);

  Request previous = target.getRequest();
  if (request.isEquivalentTo(previous)
      && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
    // 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赋值 */
  target.setRequest(request);
  /** 发起请求的开始 */
  requestManager.track(target, request);

  return target;
}

调用一个buildRequest方法返回一个Request,就是一个SingleRequest。
接着就是发调用RequestManager的track发起网路请求了。

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

将Request添加到requestd的请求队列中,判断isPaused的状态是否进行网络请求。
这个状态就是绑定生命周期的时候判断页面是否可以见,是否销毁的时候。如果是fasle就直接进行网路请求begin方法了。

@Override
public void begin() {
  synchronized (requestLock) {
    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;
      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, /* isLoadedFromAlternateCacheKey= */ false);
      return;
    }
    // Restarts for requests that are neither complete nor running can be treated as new requests
    // and can run again from the beginning.

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

进行图片宽高测量符合标准就会调用onSizeReady方法了,

@Override
public void onSizeReady(int width, int height) {
  stateVerifier.throwIfRecycled();
  synchronized (requestLock) {
    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,
            callbackExecutor);

    // 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,
    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, /* isLoadedFromAlternateCacheKey= */ false);
  return null;
}

在这里就是调用engine的load方法,在这个方法中,会根据图片的宽高等信息生成一个EngineKey,这个key是唯一的,与加载的图片一一对应。

  1. Gilde的三级缓存机制
    通过生产EngineKey 调用loadFromeMemory方法来获取图片资源EngineResource
private EngineResource<?> loadFromMemory(
  EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
  return null;
}
、/**从活动缓存中取资源*/
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
  if (VERBOSE_IS_LOGGABLE) {
    logWithTimeAndKey("Loaded resource from active resources", startTime, key);
  }
  return active;
}
  /** 从LRU中取出缓存资源,并放到活动缓存中*/
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
  if (VERBOSE_IS_LOGGABLE) {
    logWithTimeAndKey("Loaded resource from cache", startTime, key);
  }
  return cached;
}

return null;
}

into总结:
其实在into中,我们可以分为以下几个大段:

  • 首先创建图片加载请求,其实就是创建了SingleRequest;
  • 判断当前是否能够执行请求(isPaused是否为false),如果能够发起请求,最终
    调用Engine的load方法;
  • 根据图片的信息生成EngineKey,并拿这个key分别从活动缓存、Lru中获取图片资
    源,如果获取到,直接回调onResourceReady;如果没有获取到,那么就发起
    网络请求获取资源,成功之后加入活跃缓存并回调onResourceReady。
  • 在SingleRequest的onResourceReady方法中,最终其实就是调用了ImageVie w
    的setImageBitmap方法或者setImageDrawable显示图片。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容