glide 4.11.0源码分析

本文详细分析了Glide 4.11.0的源码,包括with方法的不同实现,用于根据上下文创建RequestManager。深入探讨了load方法、into方法以及数据加载和解码过程。特别是如何开启新任务加载数据,以及缓存策略的执行路径,展示了Glide如何高效地管理图片加载和缓存。
摘要由CSDN通过智能技术生成

glide 4.11.0源码分析

基础使用

添加依赖
implementation 'com.github.bumptech.glide:glide:4.11.0'
代码调用
Glide.with(this)
     .asGif()//.asBitmap()
     .load("http://www.baidu.com")
     .skipMemoryCache(false)     //关闭内存缓存
     .diskCacheStrategy(DiskCacheStrategy.NONE) //关闭磁盘缓存
     .placeholder(R.drawable.ic_launcher_background) //占位图
     .centerCrop()
     .centerInside()
     .fitCenter()
     .error(R.drawable.ic_launcher_background) //错误默认图
     .into(imageView);

with方法

with有六个重载的的方法,他们可以传入Context、Activity、Fragment、View等,方法都是通过获取RequestManagerRetriever得到RequestManager对象。

//Glide.java
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 android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}

public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}

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

传入的参数可以分为两类:
一类是Application类型,因为Application对象的生命周期就是应用程序的生命周期,因此它是和应用程序的生命周期时同步的,应用程序关闭时,Glide就会停止加载图片 ;
另外一类是非Application类型,因为这类参数的生命周期时有限的,他们随时都有可能关闭,此时给他们传一个隐藏的Fragment,如果当前的activity关闭了,就不需要继续的去请求网络,此时Glide并不知道,但是fragment可以监听到(fragment绑定在activity中),这样Glide就能够停止继续加载图片。

//RequestManagerRetriever.java
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)) {
  //传入的参数是非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());
  }
}
//传入的参数是Application类型
return getApplicationManager(context);
}

当传入的参数是非Application类型时,调用的get重载方法

public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()){
  //非UI线程,当成Application处理
  return get(activity.getApplicationContext());
} else {
  assertNotDestroyed(activity);
  FragmentManager fm = activity.getSupportFragmentManager();
  return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}

 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, /*parentHint=*/ null, isActivityVisible(activity));
}
}

当传入的参数是Application类型时,调用的方法

private RequestManager getApplicationManager(@NonNull Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
  synchronized (this) {
    if (applicationManager == null) {
      // Normally pause/resume is taken care of by the fragment we add to the fragment or
      // activity. However, in this case since the manager attached to the application will not
      // receive lifecycle events, we must force the manager to start resumed using
      // ApplicationLifecycle.

      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context.getApplicationContext());
      applicationManager =
          factory.build(
              glide,
              new ApplicationLifecycle(),
              new EmptyRequestManagerTreeNode(),
              context.getApplicationContext());
    }
  }
}

return applicationManager;
}

添加隐藏的fragment方法:
get方法中返回值对应的fragmentGet和supportFragmentGet方法内调用

private SupportRequestManagerFragment getSupportRequestManagerFragment(
  @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current =
    (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
  current = pendingSupportRequestManagerFragments.get(fm);
  if (current == null) {
    current = new SupportRequestManagerFragment();
    current.setParentFragmentHint(parentHint);
    if (isParentVisible) {
      current.getGlideLifecycle().onStart();
    }
    pendingSupportRequestManagerFragments.put(fm, current);
    fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
    handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
  }
}
return current;
}

asGif/asBitmap方法

//RequestManager.java
public RequestBuilder<GifDrawable> asGif() {
 return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}

public RequestBuilder<Bitmap> asBitmap() {
return as(Bitmap.class).apply(DECODE_TYPE_BITMAP);
}

load方法

// RequestBuilder.java
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);
}

//model就是我们传递进来的url
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
//标记已经调用过load方法
isModelSet = true;
return this;
}

into方法

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

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

//RequestManager.java
 synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
//控件生命周期进行管理
targetTracker.track(target);
//处理请求
requestTracker.runRequest(request);
}

//开始跟踪指定的请求
  public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
   //当glide不关闭时执行请求方法
  request.begin();
} else {
  request.clear();
  if (Log.isLoggable(TAG, Log.VERBOSE)) {
    Log.v(TAG, "Paused, delaying request");
  }
  pendingRequests.add(request);
}
}

//SingleRequest.java
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);
    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 {
     //没有设置控件的宽高
    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));
  }
}
}

 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;
  }
  //当状态为运行的时候调用Engine的load方法
  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));
  }
}
}

//Engine.java
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;
//构造图片缓存的Key
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.
//存在缓存数据,直接调用SingleRequest中的onResourceReady
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}

获取缓存的方法

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

//从缓存中加载
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
  if (VERBOSE_IS_LOGGABLE) {
    logWithTimeAndKey("Loaded resource from cache", startTime, key);
  }
  return cached;
}

return null;
}

存在缓存数据

public void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
Resource<?> toRelease = null;
try {
  synchronized (requestLock) {
    loadStatus = null;
    if (resource == null) {
      GlideException exception =
          new GlideException(
              "Expected to receive a Resource<R> with an "
                  + "object of "
                  + transcodeClass
                  + " inside, but instead got null.");
      onLoadFailed(exception);
      return;
    }

    Object received = resource.get();
    if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
      toRelease = resource;
      this.resource = null;
      GlideException exception =
          new GlideException(
              "Expected to receive an object of "
                  + transcodeClass
                  + " but instead"
                  + " got "
                  + (received != null ? received.getClass() : "")
                  + "{"
                  + received
                  + "} inside"
                  + " "
                  + "Resource{"
                  + resource
                  + "}."
                  + (received != null
                      ? ""
                      : " "
                          + "To indicate failure return a null Resource "
                          + "object, rather than a Resource object containing null data."));
      onLoadFailed(exception);
      return;
    }

    if (!canSetResource()) {
      toRelease = resource;
      this.resource = null;
      // We can't put the status to complete before asking canSetResource().
      status = Status.COMPLETE;
      return;
    }

    onResourceReady((Resource<R>) resource, (R) received, dataSource);
  }
} finally {
  if (toRelease != null) {
    engine.release(toRelease);
  }
}
}
开启新的任务进行数据的加载(也就是第一次加载数据的步骤)

下面的方法创建了EngineJob和DecodeJob两个对象,EngineJob内维护了一个线程池,来管理资源;DecodeJob实现了Runnable,进行数据的加载,是线程中当前的一个任务。

private <R> LoadStatus waitForExistingOrStartNewJob(
  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,
  EngineKey key,
  long startTime) {

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<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, callbackExecutor);
engineJob.start(decodeJob);

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


//DecodeJob.java
  public void run() {
// This should be much more fine grained, but since Java's thread pool implementation silently
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值