Glide源码分析

一、源码分析:
1、with()
2、load()
3、into()
二、缓存机制
1、Glide缓存机制简介
1.1缓存的图片资源
Glide 需要缓存的 图片资源 分为两类:
原始图片(Source) :即图片源的图片初始大小 & 分辨率。
转换后的图片(Result) :经过尺寸缩放和大小压缩等处理后的图片。
当使用 Glide加载图片时,Glide默认 根据 View视图对图片进行压缩 & 转换,而不显示原始图(这也是Glide加载速度高于Picasso的原因)。
1.2 缓存机制设计
Glide的缓存功能设计成 二级缓存:内存缓存和磁盘缓存。
缓存读取顺序:内存缓存 –> 磁盘缓存 –> 网络。
内存缓存默认开启Glide中,内存缓存 & 磁盘缓存相互不影响,独立配置。
可缓存原始图片 & 缓存转换过后的图片,用户自行设置
2、Glide 缓存功能介绍
Glide 的缓存功能分为:内存缓存 & 磁盘缓存
2.1、内存缓存
作用:防止应用重复将图片数据读取到内存当中只缓存转换过后的图片。
实现原理:Glide的内存缓存实现是基于:LruCache 算法(Least Recently Used) 和弱引用机制
LruCache算法:将 最近使用的对象 用强引用的方式 存储在LinkedHashMap中 当缓存满时 ,将最近最少使用的对象从内存中移除 。
弱引用:弱引用的对象具备更短生命周期,当JVM进行垃圾回收时,一旦发现弱引用对象,都会进行回收(无论内存充足否)
2.2、磁盘缓存
作用:防止应用 重复从网络或其他地方重复下载和读取数据
实现原理 :使用Glide 自定义的DiskLruCache算法
该算法基于 Lru 算法中的DiskLruCache算法,具体应用在磁盘缓存的需求场景中
该算法被封装到Glide自定义的工具类中(该工具类基于Android 提供的DiskLruCache工具类

三、 Glide 缓存流程 解析
1、生成缓存Key
Glide 实现内存 & 磁盘缓存是根据图片的缓存Key进行唯一标识,即根据图片的缓存Key去缓存区找对应的缓存图片,生成缓存 Key 的代码发生在Engine类的 load()中

  public synchronized <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<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        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 (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }

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

2、创建缓存对象 LruResourceCache
LruResourceCache对象是在创建 Glide 对象时创建的,就是GlideBuilder类的memoryCache

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

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

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

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

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

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

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

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

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

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

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

    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions,
        defaultRequestListeners,
        isLoggingRequestOriginsEnabled);
  }

3、从内存缓存中获取缓存图片
没错,还是Engine类,loadFromActiveResources()和loadFromCache()
弱引用机制的内存缓存获取缓存

@Nullable
  private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
      return null;
    }
    EngineResource<?> active = activeResources.get(key);
    if (active != null) {
      active.acquire();
    }

    return active;
  }

LruCache算法机制的内存缓存获取缓存

  private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
      return null;
    }

    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {
      cached.acquire();
      activeResources.activate(key, cached);
    }
    return cached;
  }

4、开启加载图片线程
若无法从内存缓存里获得缓存的图片,Glide就会开启加载图片的线程
但在该线程开启后,Glide并不会马上去网络 加载图片,而是采取采用Glide的第2级缓存:磁盘缓存去获取缓存图片
5、从磁盘缓存中获取缓存图片
若无法从内存缓存里获得缓存的图片,就会磁盘缓存去获取缓存图片
6、从网络获取图片资源

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

7、写入磁盘缓存
8、写入内存缓存
9、写入弱应用缓存
10、显示图片
在将图片写入内存缓存和磁盘缓存后,图片最终显示出来
在下次加载时,将通过二级缓存从而提高图片加载效率。

推荐阅读更多精彩内容