Glide源码解析

一、缓存

内存缓存和磁盘缓存都用了LRUcache算法

LRUcache算法

实现原理:内部维护了一个LinkedHashMap

LinkedHashMap的构造方法:

//loadFactor为加载因子,默认是3/4,其实该参数并没有并用到,只要传入大于0的float值即可
//accessOrder如果为true,则表示按最近访问顺序排序;false表示按插入顺序排序
 public LinkedHashMap(int initialCapacity,float loadFactor, boolean accessOrder) {
    super(initialCapacity, loadFactor);
    this.accessOrder = accessOrder;
}

关于loadFactor并没有用到的源码

//loadFactor传递给了父类构造方法
 public LinkedHashMap(int initialCapacity,float loadFactor, boolean accessOrder) {
    super(initialCapacity, loadFactor);
    this.accessOrder = accessOrder;
}
//HashMap为LinkedHashMap的父类
//loadFactor并没有赋值给成员变量,只是做了一层合法性判断
 public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY) {
            initialCapacity = MAXIMUM_CAPACITY;
        } else if (initialCapacity < DEFAULT_INITIAL_CAPACITY) {
            initialCapacity = DEFAULT_INITIAL_CAPACITY;
        }

        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        // Android-Note: We always use the default load factor of 0.75f.

        // This might appear wrong but it's just awkward design. We always call
        // inflateTable() when table == EMPTY_TABLE. That method will take "threshold"
        // to mean "capacity" and then replace it with the real threshold (i.e, multiplied with
        // the load factor).
        threshold = initialCapacity;
        init();
    }
//hashmap中写死了该加载因子为0.75;所以只要传入任意合法的值皆可以,但都会被忽视
//这样做据说是0.75的效率最高
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// Android-Note: We always use a load factor of 0.75 and ignore any explicitly selected values
final float loadFactor = DEFAULT_LOAD_FACTOR;

loadFactor有什么用?

用于判断,何时map容器需要扩容;默认map初始化时,容量为16,当达到一个阈值时,需要扩容;该loadFactor(称为加载因子),用于判断何时达到该阈值

何时去清理内存?

Glide清理内存的机制是实现ComponentCallbacks2接口。

也就是说Glide本身没有去判断何时内存不足或者何时需要去清理图片内存,完全依赖了安卓的机制

关于ComponentCallback2

  • 是一个细粒度的内存回收管理回调
  • android中的基本组件Application、Activity、Service、ContentProvider、Fragment均实现了该回调
  • 开发者应该实现onTrimMemory(int)方法,细粒度release 内存,参数可以体现不同程度的内存可用情况
  • 响应onTrimMemory回,开发者的app会直接受益,有利于用户体验,系统更有可能让app存活的更持久;不响应onTrimMemory回调,系统更有可能kill 进程

如何体现细粒度的回调

//体现在该回调方法传入的参数中
void onTrimMemory(int level);

//该参数有以下几种粒度:(具体见源码)

static final int TRIM_MEMORY_COMPLETE = 80;
    
static final int TRIM_MEMORY_MODERATE = 60;
    
static final int TRIM_MEMORY_BACKGROUND = 40;
    
static final int TRIM_MEMORY_UI_HIDDEN = 20;

static final int TRIM_MEMORY_RUNNING_CRITICAL = 15;

static final int TRIM_MEMORY_RUNNING_LOW = 10;

static final int TRIM_MEMORY_RUNNING_MODERATE = 5;

内存维护的关键类

RequestManager

Glide.with(Context context)//该参数可以是Activity;如果为Activity,则在该RequestManager下创建的load将会与该Activity的生命周期绑定;
Glide.with(Activity activity)//该参数也可以是Fragment;同理,生命周期也将与该fagment绑定
Glide.with(Fragment fragment)
//这里以Activity参数为例,看如何将RequestManager与actvivity生命周期绑定
public static RequestManager with(Activity activity) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(activity);
}

//通过RequestManagerRetriever的get方法获取RequestManager
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
 public RequestManager get(Activity activity) {
    if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      //获取到该activity下的FragmentManager
      android.app.FragmentManager fm = activity.getFragmentManager();
      //传入fragmentGet方法
      return fragmentGet(activity, fm, null);
    }
}

RequestManager fragmentGet(Context context, android.app.FragmentManager fm,
      android.app.Fragment parentHint) {
    //通过FragmentManager创建一个Fragment
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
    //接下来的事情是将该fragment和RequestManager绑定
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
        // TODO(b/27524013): Factor out this Glide.get() call.
        Glide glide = Glide.get(context);
        //requestManager中传入RequestManagerFragment的Lifecycle回调,通过构造方法传入
        requestManager =new RequestManager(glide, current.getLifecycle(), current.getRequestManagerTreeNode());
        //RequestManagerFragment中传入requestManager引用
        current.setRequestManager(requestManager);
    }
    return requestManager;
  }
  
//接下来就是回调了,看RequestManagerFragment的代码
public class RequestManagerFragment extends Fragment {

    ...
    
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            registerFragmentWithRoot(activity);
        } catch (IllegalStateException e) {
            // OnAttach can be called after the activity is destroyed, see #497.
            if (Log.isLoggable(TAG, Log.WARN)) {
            Log.w(TAG, "Unable to register fragment with root", e);
        }
    }
  }

    @Override
    public void onStart() {
        super.onStart();
        lifecycle.onStart();
    }

    @Override
    public void onStop() {
        super.onStop();
        lifecycle.onStop();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        lifecycle.onDestroy();
        unregisterFragmentWithRoot();
    }

    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
        // If an activity is re-created, onTrimMemory may be called before a manager is ever put.
        // See #329.
        if (requestManager != null) {
            //回调requestManager
            requestManager.onTrimMemory(level);
        }
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        // If an activity is re-created, onLowMemory may be called before a manager is ever put.
        // See #329.
        if (requestManager != null) {
         //回调requestManager
            requestManager.onLowMemory();
        }
    }

}

//上述Fragmetn中的onTrimMemory和onLowMemory方法会一层一层往外回调
//先到RetrofitMangeger中
//RetrofitMangeger类回调Glide的Context中的方法
public void onTrimMemory(int level) {
    glide.getGlideContext().onTrimMemory(level);
}

/**
 * @see android.content.ComponentCallbacks2#onLowMemory()
 */
public void onLowMemory() {
    glide.getGlideContext().onLowMemory();
}

//GlideContext最终就回调ComponentCallbacks2接口了,该接口有Glide类实现
@Override
public void onTrimMemory(int level) {
    componentCallbacks.onTrimMemory(level);
}

@Override
public void onLowMemory() {
    componentCallbacks.onLowMemory();
}

//Glide方法源码
@Override
public void onTrimMemory(int level) {
    trimMemory(level);
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    // Do nothing.
}

@Override
public void onLowMemory() {
    clearMemory();
}

public void trimMemory(int level) {
    // Engine asserts this anyway when removing resources, fail faster and consistently
    Util.assertMainThread();
    // memory cache needs to be trimmed before bitmap pool to trim re-pooled Bitmaps too. See #687.
    memoryCache.trimMemory(level);
    bitmapPool.trimMemory(level);
    arrayPool.trimMemory(level);
}
  
@Override
public void onLowMemory() {
    clearMemory();
}

//最终通过LRUcache算法清理内存
//这里一个小细节是,会判断app是否是后台,后台进程会将内存全部清理;
//前台进程通过LRU清理一半内存
public void trimMemory(int level) {
    if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
      // Nearing middle of list of cached background apps
      // Evict our entire bitmap cache
      clearMemory();
    } else if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
      // Entering list of cached background apps
      // Evict oldest half of our bitmap cache
      trimToSize(getCurrentSize() / 2);
    }
}

二、load的过程

1.RequestManager调用laod方法,会创建一个RequestBuilder对象

2.紧接着调用RequestBuilder的into()方法

into()有多个重载方法

已最常见的ImageView参数为例

public Target<TranscodeType> into(ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      if (requestOptions.isLocked()) {
        requestOptions = requestOptions.clone();
      }
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions.optionalCenterCrop(context);
          break;
        case CENTER_INSIDE:
          requestOptions.optionalCenterInside(context);
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions.optionalFitCenter(context);
          break;
        //$CASES-OMITTED$
        default:
          // Do nothing.
      }
    }
    //最终调用的是另个一重载的into();
    //该方法创建了一个Target对象
    return into(context.buildImageViewTarget(view, transcodeClass));
  }

以上target对象的创建过程:

public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
    if (Bitmap.class.equals(clazz)) {
      return (Target<Z>) new BitmapImageViewTarget(view);
      //这里根据上上面代码传进来的transcodeClass来创建对应的target,在这个逻辑中创建的是DrawableImageViewTarget
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      return (Target<Z>) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }

为什么这里的逻辑创建的是DrawableImageViewTarget?

//因为在一开始调用load的时候,默认transcodeClass是Drawable.class
public RequestBuilder<Drawable> load(@Nullable Object model) {
    return asDrawable().load(model);
}
  
public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class).transition(new DrawableTransitionOptions());
}

public <ResourceType> RequestBuilder<ResourceType> as(Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide.getGlideContext(), this, resourceClass);
}

接着跟踪另一个重载的into方法

public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    Request previous = target.getRequest();

    if (previous != null) {
      requestManager.clear(target);
    }

    requestOptions.lock();
    Request request = buildRequest(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
}

每次为当前target创建一个请求之前,会先去拿该target之前绑定的request,如果有,会清除掉该request,重新创建绑定

创建request的过程,核心代码:

private Request buildRequestRecursive(Target<TranscodeType> target,
      @Nullable ThumbnailRequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority, int overrideWidth, int overrideHeight) {
    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;
      if (DEFAULT_ANIMATION_OPTIONS.equals(thumbTransitionOptions)) {
        thumbTransitionOptions = transitionOptions;
      }

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

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

      ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
      Request fullRequest = obtainRequest(target, requestOptions, coordinator,
          transitionOptions, priority, overrideWidth, overrideHeight);
      isThumbnailBuilt = true;
      // Recursively generate thumbnail requests.
      Request thumbRequest = thumbnailBuilder.buildRequestRecursive(target, coordinator,
          thumbTransitionOptions, thumbPriority, thumbOverrideWidth, thumbOverrideHeight);
      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(parentCoordinator);
      Request fullRequest = obtainRequest(target, requestOptions, coordinator, transitionOptions,
          priority, overrideWidth, overrideHeight);
      BaseRequestOptions<?> thumbnailOptions = requestOptions.clone()
          .sizeMultiplier(thumbSizeMultiplier);

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

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

第一个if,thumbnailBuilder,如果没有调用thumbnail(@Nullable RequestBuilder<TranscodeType> thumbnailRequest),处理小图逻辑不用管;

第二if,thumbSizeMultiplier,一样如果没有调用thumbnail(float sizeMultiplier),处理小图逻辑也不用管

最后一个else,很关键,obtainRequest();

private Request obtainRequest(Target<TranscodeType> target,
      BaseRequestOptions<?> requestOptions, RequestCoordinator requestCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority,
      int overrideWidth, int overrideHeight) {
    requestOptions.lock();

    return SingleRequest.obtain(
        context,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        requestListener,
        requestCoordinator,
        context.getEngine(),
        transitionOptions.getTransitionFactory());
  }

其实是创建了一个SingleRequest对象

再回到into()方法中,重新贴下代码:

public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    Request previous = target.getRequest();

    if (previous != null) {
      requestManager.clear(target);
    }

    requestOptions.lock();
    Request request = buildRequest(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
}

request已经创建了,其实是一个SingleRequest对象

接着将target和该request对象绑定

接着调用requestManager.track(target, request);//很关键

//requestManager的track方法
void track(Target<?> target, Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
}

这里有两个对象,一个是targetTracker,一个是requestTracker

targetTracker用来存储当前正被激活使用的target对象,调用一次track方法,就会将该target对象存储起来。并且用来管理requestmanger下创建的所有target的生命周期

看源码:

public final class TargetTracker implements LifecycleListener {
  private final Set<Target<?>> targets =
      Collections.newSetFromMap(new WeakHashMap<Target<?>, Boolean>());

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

  public void untrack(Target<?> target) {
    targets.remove(target);
  }

  @Override
  public void onStart() {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onStart();
    }
  }

  @Override
  public void onStop() {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onStop();
    }
  }

  @Override
  public void onDestroy() {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onDestroy();
    }
  }

  public List<Target<?>> getAll() {
    return new ArrayList<>(targets);
  }

  public void clear() {
    targets.clear();
  }
}

RequestTracker对象,很重要,用来管理请求,包括开启、取消、重新开始请求等

所以requestTracker.runRequest(request);该方法用来开启请求

public void runRequest(Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      pendingRequests.add(request);
    }
}

先将request对象存在弱引用中,优化内存。

private final Set<Request> requests =
      Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());

然后调用 request.begin();

之前得出结论改request对象为SingleRequest,所以定位到SingleRequest的begin()方法

public void begin() {
    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;
    }

    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 (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
}

这里就是要先拿到size,然后去加载

if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      target.getSize(this);
    }
}

这两个最终都是在onSizeReady中处理核心代码:

public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      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 (Log.isLoggable(TAG, Log.VERBOSE)) {
      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.getOptions(),
        requestOptions.isMemoryCacheable(),
        requestOptions.getUseUnlimitedSourceGeneratorsPool(),
        requestOptions.getOnlyRetrieveFromCache(),
        this);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
}

核心是调用了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,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb) {
    Util.assertMainThread();
    long startTime = LogTime.getLogTime();

    //创建key
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
    //通过key去拿缓存
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
        //如果缓存存在,则回调onResourceReady()方法,把cache回传过去
        cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Loaded resource from cache", startTime, key);
        }
      return null;
    }
    通过key去拿第二层缓存
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
        //同理,如果缓存存在,则回调onResourceReady()方法,把cache回传过去
        cb.onResourceReady(active, DataSource.MEMORY_CACHE);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          logWithTimeAndKey("Loaded resource from active resources", startTime, key);
        }
        return null;
    }

    EngineJob<?> current = jobs.get(key);
    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开启网络请求
    EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
        useUnlimitedSourceExecutorPool);
    DecodeJob<R> decodeJob = decodeJobFactory.build(
        glideContext,
        model,
        key,
        signature,
        width,
        height,
        resourceClass,
        transcodeClass,
        priority,
        diskCacheStrategy,
        transformations,
        isTransformationRequired,
        onlyRetrieveFromCache,
        options,
        engineJob);
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);
    //其实实际的工作是decodeJob在做
    engineJob.start(decodeJob);

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

核心代码decodejob的run方法

@Override
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.
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      //关键代码
      runWrapped();
    } catch (RuntimeException e) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "DecodeJob threw unexpectedly"
            + ", isCancelled: " + isCancelled
            + ", stage: " + stage, e);
      }
      // When we're encoding we've already notified our callback and it isn't safe to do so again.
      if (stage != Stage.ENCODE) {
        notifyFailed();
      }
      if (!isCancelled) {
        throw e;
      }
    }
}

run方法中的核心代码: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);
    }
}

1、刚进来runReason为INITIALIZE,进入第一个case

2、第一个case的逻辑:

getNextStage的逻辑:返回当前阶段的下一个阶段。

初始化阶段之后,如果需要磁盘缓存resocueCache,则下一个阶段是磁盘缓存resocueCache;

内存缓存之后,如果需要磁盘缓存DataCache,则下一个阶段是磁盘缓存DataCache;

磁盘缓存之后,如果需要从网络请求中拿数据,则下一个阶段是请求网络,否则下一个阶段是结束。

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

之后调用getNextGenerator方法 该方法是根据当前的阶段,创建对应的Generator 赋值给currentGenerator

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

最后是调用runGenerators方法 核心代码是调用了currentGenerator.startNext()方法

private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    //核心代码在这里
    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();
    }

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

根据上面currentGenerator的创建方法可知,不同的阶段返回的generator不同

startNext()方法也不同。

并且while循环的判断条件可知,只要请求没有取消,currentGenerator不为null,就会取下一个currentGenerator,并且调用该currentGenerator的startNext()方法,直到stage == Stage.SOURCE。

先来看一下不同的currentGenerator的startNext()方法:

ResourceCacheGenerator

public boolean startNext() {
    List<Key> sourceIds = helper.getCacheKeys();
    if (sourceIds.isEmpty()) {
      return false;
    }
    List<Class<?>> resourceClasses = helper.getRegisteredResourceClasses();
    while (modelLoaders == null || !hasNextModelLoader()) {
      resourceClassIndex++;
      if (resourceClassIndex >= resourceClasses.size()) {
        sourceIdIndex++;
        if (sourceIdIndex >= sourceIds.size()) {
          return false;
        }
        resourceClassIndex = 0;
      }

      Key sourceId = sourceIds.get(sourceIdIndex);
      Class<?> resourceClass = resourceClasses.get(resourceClassIndex);
      Transformation<?> transformation = helper.getTransformation(resourceClass);

      currentKey = new ResourceCacheKey(sourceId, helper.getSignature(), helper.getWidth(),
          helper.getHeight(), transformation, resourceClass, helper.getOptions());
      cacheFile = helper.getDiskCache().get(currentKey);
      if (cacheFile != null) {
        this.sourceKey = sourceId;
        modelLoaders = helper.getModelLoaders(cacheFile);
        modelLoaderIndex = 0;
      }
    }

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
      loadData =
          modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
              helper.getOptions());
      if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }

    return started;
}

DataCacheGenerator

public boolean startNext() {
    while (modelLoaders == null || !hasNextModelLoader()) {
      sourceIdIndex++;
      if (sourceIdIndex >= cacheKeys.size()) {
        return false;
      }

      Key sourceId = cacheKeys.get(sourceIdIndex);
      Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
      cacheFile = helper.getDiskCache().get(originalKey);
      if (cacheFile != null) {
        this.sourceKey = sourceId;
        modelLoaders = helper.getModelLoaders(cacheFile);
        modelLoaderIndex = 0;
      }
    }

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
      loadData =
          modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
              helper.getOptions());
      if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
}

SourceGenerator

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;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
}

关于ResourceCache和DataCache,都是磁盘缓存,除了缓存的key不一样,暂时我还不知道有其他区别,待深入了解。

ResourceCache和DataCache最终生成的key,都需要用到loadData中的key,该key可以继承LoadData来自定义。

//ResourceCacheKey
currentKey = new ResourceCacheKey(sourceId, helper.getSignature(), helper.getWidth(),
          helper.getHeight(), transformation, resourceClass, helper.getOptions());
//DataCacheKey
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());

从源码上看,两者的区别应该是前者根据图片唯一key和宽高等资源属性生成key;后者指根据图片的唯一key缓存

接下来两个解析缓存文件的思路一致:

从register中注册的loaders中,找到能解析file的loader

modelLoaders = helper.getModelLoaders(cacheFile);

将要解析的file和一些配置信息传入loaddata对象

loadData =
          modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
              helper.getOptions());

解析file

loadData.fetcher.loadData(helper.getPriority(), this);

重点需要分析SourceGenerator

先根据图片key缓存到磁盘

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

之后也是根据model,从register中注册的loaddata中获取匹配的

然后调用对应的loaddata中fetcher的loaddta方法,注意这边会传入回调,下面源码中的this就是回调

while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
}

最终的网络请求部分交给了loadData中的fetcher对象,调用fetcher对象的loadData方法

如:

public void loadData(Priority priority, DataCallback<? super InputStream> callback) {
    request = requestFactory.create(url.toStringUrl(), callback, glideToVolleyPriority(priority),
        url.getHeaders());
    requestQueue.add(request);
}

或者:

public void loadData(Priority priority, final DataCallback<? super InputStream> callback) {
    Request.Builder requestBuilder = new Request.Builder().url(url.toStringUrl());
    for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
      String key = headerEntry.getKey();
      requestBuilder.addHeader(key, headerEntry.getValue());
    }
    Request request = requestBuilder.build();

    call = client.newCall(request);
    call.enqueue(new okhttp3.Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
          Log.d(TAG, "OkHttp failed to obtain result", e);
        }
        callback.onLoadFailed(e);
      }

      @Override
      public void onResponse(Call call, Response response) throws IOException {
        responseBody = response.body();
        if (response.isSuccessful()) {
          long contentLength = responseBody.contentLength();
          stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);
        } else if (Log.isLoggable(TAG, Log.DEBUG)) {
          Log.d(TAG, "OkHttp got error response: " + response.code() + ", " + response.message());
        }
        callback.onDataReady(stream);
      }
    });
}

不管哪种方式,最终都会通过callback对象,将请求完成的状态和数据回调出去

着重关注成功之后的回调

这里又通过cb回调出去了,这个cb是DecodeJob对象

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.reschedule();
    } else {
      cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
          loadData.fetcher.getDataSource(), originalKey);
    }
}

如果不需要缓存,回调DecodeJob的onDataFetcherReady方法

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

最终调用decodeFromRetrievedData

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);
      exceptions.add(e);
    }
    if (resource != null) {
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
}

获取到resource;

再一层一层往外回调出去:

到singlerequest的回调

private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
    // We must call isFirstReadyResource before setting status.
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;

    if (glideContext.getLogLevel() <= Log.DEBUG) {
      Log.d(GLIDE_TAG, "Finished loading " + result.getClass().getSimpleName() + " from "
          + dataSource + " for " + model + " with size [" + width + "x" + height + "] in "
          + LogTime.getElapsedMillis(startTime) + " ms");
    }

    if (requestListener == null
        || !requestListener.onResourceReady(result, model, target, dataSource, isFirstResource)) {
      Transition<? super R> animation =
          animationFactory.build(dataSource, isFirstResource);
      target.onResourceReady(result, animation);
    }

    notifyLoadSuccess();
}

再最终到各个target的回调

target.onResourceReady(result, animation);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值