美文网首页UI
Fresco源码浅析-ImagePipeline模块(三)

Fresco源码浅析-ImagePipeline模块(三)

作者: panda_Vicky | 来源:发表于2016-06-01 19:23 被阅读1909次

ImagePipeline是Fresco读取数据的整个调度系统,作为一个图片加载组件,主要工作流程为:

  • 检查内存缓存
  • 检查磁盘缓存
  • 文件读取或网络请求,并存储到各个缓存。
    官方流程图如下:


    imagepipeline.png

这和主要的图片加载逻辑基本类似,既然如此,那我们就从图片加载组件最主要的两个方面入手分析源码:
1) 如何自定义缓存线程和加载线程的配置;
2) 缓存设计算法。

首先看第一个问题,要看ImagePipeline的配置,我们来分析一下ImagePipelineConfig的源码:

  @Nullable private final AnimatedImageFactory mAnimatedImageFactory;
  private final Bitmap.Config mBitmapConfig;
  private final Supplier<MemoryCacheParams> mBitmapMemoryCacheParamsSupplier; //内存缓存数据的策略
  private final CacheKeyFactory mCacheKeyFactory; //缓存键值对的获取
  private final Context mContext;
  private final boolean mDownsampleEnabled;
  private final boolean mDecodeMemoryFileEnabled;
  private final FileCacheFactory mFileCacheFactory; // 文件缓存键值对
  private final Supplier<MemoryCacheParams> mEncodedMemoryCacheParamsSupplier;  //原码内存缓存参数
  private final ExecutorSupplier mExecutorSupplier;  //获取线程池
  private final ImageCacheStatsTracker mImageCacheStatsTracker;//Cache埋点工具
  @Nullable private final ImageDecoder mImageDecoder; //解码器
  private final Supplier<Boolean> mIsPrefetchEnabledSupplier;
  private final DiskCacheConfig mMainDiskCacheConfig;//磁盘缓存配置
  private final MemoryTrimmableRegistry mMemoryTrimmableRegistry;
  private final NetworkFetcher mNetworkFetcher; //网络获取器
  @Nullable private final PlatformBitmapFactory mPlatformBitmapFactory;
  private final PoolFactory mPoolFactory;
  private final ProgressiveJpegConfig mProgressiveJpegConfig;  //渐进图片配置
  private final Set<RequestListener> mRequestListeners;
  private final boolean mResizeAndRotateEnabledForNetwork;
  private final DiskCacheConfig mSmallImageDiskCacheConfig;//小图缓存配置
  private final ImagePipelineExperiments mImagePipelineExperiments;
  ...

ImagePipeline的可配置项如下:

ImagePipelineConfig config = ImagePipelineConfig.newBuilder()
    .setBitmapMemoryCacheParamsSupplier(bitmapCacheParamsSupplier)  //bitmap缓存配置
    .setCacheKeyFactory(cacheKeyFactory) //设置缓存键值对
    .setEncodedMemoryCacheParamsSupplier(encodedCacheParamsSupplier)//设置原码内存缓存配置
    .setExecutorSupplier(executorSupplier) //各种线程池
    .setImageCacheStatsTracker(imageCacheStatsTracker)//缓存打点
    .setMainDiskCacheConfig(mainDiskCacheConfig) //主磁盘缓存
    .setMemoryTrimmableRegistry(memoryTrimmableRegistry) 
    .setNetworkFetchProducer(networkFetchProducer)//网络请求配置
    .setPoolFactory(poolFactory)
    .setProgressiveJpegConfig(progressiveJpegConfig)//渐进图片配置
    .setRequestListeners(requestListeners)//请求监听
    .setSmallImageDiskCacheConfig(smallImageDiskCacheConfig)//小图缓存
    .build();
Fresco.initialize(context, config);

ImagePipeline用到了三个缓存,首先是DiskCache,然后还有两个MemoryCache,分别是保存已解码Bitmap的和保存EncodedImage的缓存。Fresco将未解码的原始数据也进行了内存缓存,然后根据是否旋转或者缩放以及解码质量进行解码成bitmap存放内存空间,其实在我所接触的应用场景中这部分内容其实是不太需要的,因为一张图片基本上只在一个地方使用,即使多处使用也不太需要这么复杂的变换,可能Fresco想的比较周到吧。
内存缓存使用的是通用的lru算法(最近最少使用原则),内存缓存的设计代码在CountingMemoryCache,CountingMemoryCache是一个基于LRU策略来管理缓存中元素的一个类,它实现的trim()方法可以根据Type的不同来采取不同策略的回收为:

/**
 * Layer of memory cache stack responsible for managing eviction of the the cached items.
 *
 * <p> This layer is responsible for LRU eviction strategy and for maintaining the size boundaries
 * of the cached items.
 *
 * <p> Only the exclusively owned elements, i.e. the elements not referenced by any client, can be
 * evicted.
 *
 * @param <K> the key type
 * @param <V> the value type
 */
@ThreadSafe
public class CountingMemoryCache<K, V> implements MemoryCache<K, V>, MemoryTrimmable {
   ...//省略代码
    /** Trims the cache according to the specified trimming strategy and the given trim type. */
  @Override
  public void trim(MemoryTrimType trimType) {
    ArrayList<Entry<K, V>> oldEntries;
    final double trimRatio = mCacheTrimStrategy.getTrimRatio(trimType);
    synchronized (this) {
      int targetCacheSize = (int) (mCachedEntries.getSizeInBytes() * (1 - trimRatio));
      int targetEvictionQueueSize = Math.max(0, targetCacheSize - getInUseSizeInBytes());
      oldEntries = trimExclusivelyOwnedEntries(Integer.MAX_VALUE, targetEvictionQueueSize);
      makeOrphans(oldEntries);
    }
    maybeClose(oldEntries);
    maybeNotifyExclusiveEntryRemoval(oldEntries);
    maybeUpdateCacheParams();
    maybeEvictEntries();
  }
  ...//省略代码
}

Fresco使用的黑科技还有很多,它是一份巨大的宝藏等着挖掘,我只是粗浅的总结了部分我get到的点,以后进一步深入学习中再和大家分享。

相关文章

网友评论

    本文标题:Fresco源码浅析-ImagePipeline模块(三)

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