美文网首页
Glide源码分析

Glide源码分析

作者: 爱码士平头哥 | 来源:发表于2019-03-19 12:04 被阅读0次

    一、源码分析:
    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、显示图片
    在将图片写入内存缓存和磁盘缓存后,图片最终显示出来
    在下次加载时,将通过二级缓存从而提高图片加载效率。

    相关文章

      网友评论

          本文标题:Glide源码分析

          本文链接:https://www.haomeiwen.com/subject/brtbmqtx.html