Fresco图片框架实现原理(一):初始化

2018-04-14  本文已影响204人  木有粗面_9602

使用Fresco之前,一定先要进行初始化,一般初始化的工作会在Application.onCreate()完成,当然也可以在使用Drawee之前完成。
Fresco本身提供了两种初始化方式,一种是使用使用默认配置初始化,另一种是使用用户自定义配置

开始初始化

Fresco.initialized(context)

默认参数进行初始化

public static void initialize(Context context) {
  initialize(context, null, null);
}

其中ImagePipeline 负责获取图像数据,可以是网络图片,也可以是本地图片。这里用一个 FactoryImagePipelineFactory 来创建默认的 ImagePipleline。

用户自定义配置

 public static void initialize(
      Context context, ImagePipelineConfig imagePipelineConfig) {
    initialize(context, imagePipelineConfig, null);
  }

归根接地

  /** Initializes Fresco with the specified config. */
  public static void initialize(
      Context context,
      @Nullable ImagePipelineConfig imagePipelineConfig,
      @Nullable DraweeConfig draweeConfig) {
    if (sIsInitialized) {
      FLog.w(
          TAG,
          "Fresco has already been initialized! `Fresco.initialize(...)` should only be called " +
            "1 single time to avoid memory leaks!");
    } else {
      sIsInitialized = true;
    }
    // we should always use the application context to avoid memory leaks
   总是使用Application的Context来避免内存泄漏
    context = context.getApplicationContext();
     
   第一. 初始化ImagePipelineFactory
    if (imagePipelineConfig == null) {
      ImagePipelineFactory.initialize(context);
    } else {
      ImagePipelineFactory.initialize(imagePipelineConfig);
    }
   第二, 初始化Drawee模块
    initializeDrawee(context, draweeConfig);
  }

从上面代码可以看出初始化其实是做了两个工作,一是初始化ImagePipelineFactory,二是初始化Drawee模块。
ImagePipelineFactory.initialize()方法和initializeDrawee(context, draweeConfig)方法
initializeDrawee方法

  /** Initializes Drawee with the specified config. */
用具体的draweeConfig来初始化
  private static void initializeDrawee(
      Context context,  DraweeConfig draweeConfig) {
    sDraweeControllerBuilderSupplier =
        new PipelineDraweeControllerBuilderSupplier(context, draweeConfig);
    SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier);
  }

这段代码其实是在设置SimpleDraweeView模块的DraweeController.

ImagePipelineFactory.initialize()方法

初始化ImagePipelineFactory
public static void initialize(ImagePipelineConfig imagePipelineConfig) {
    sInstance = new ImagePipelineFactory(imagePipelineConfig);
  }

  私有final变量 ImagePipelineConfig 
  private final ImagePipelineConfig mConfig;
  负责管理缓存项目驱逐的内存缓存堆栈层。
  private CountingMemoryCache<CacheKey, CloseableImage>   mBitmapCountingMemoryCache;
  图像管道内存缓存接口
  private MemoryCache<CacheKey, CloseableImage> mBitmapMemoryCache;
  负责管理缓存项目驱逐的内存缓存堆栈层。 解码内存
  private CountingMemoryCache<CacheKey, PooledByteBuffer> mEncodedCountingMemoryCache;
   图像管道内存缓存接口 ,解码缓存
  private MemoryCache<CacheKey, PooledByteBuffer> mEncodedMemoryCache;
  BufferedDiskCache提供了get和put操作来负责调度磁盘缓存读/写
  private BufferedDiskCache mMainBufferedDiskCache;
  主文件缓存
  private FileCache mMainFileCache;
  图片解码接口
  private ImageDecoder mImageDecoder;
  图像管道配置
  private ImagePipeline mImagePipeline;
  生产者工厂
  private ProducerFactory mProducerFactory;
  private ProducerSequenceFactory mProducerSequenceFactory;
 小图片磁盘缓存
  private BufferedDiskCache mSmallImageBufferedDiskCache;
  小图片文件缓存
  private FileCache mSmallImageFileCache;
  private MediaVariationsIndex mMediaVariationsIndex;

  private PlatformBitmapFactory mPlatformBitmapFactory;
  平台解码器
  private PlatformDecoder mPlatformDecoder;

  private AnimatedFactory mAnimatedFactory;

  public ImagePipelineFactory(ImagePipelineConfig config) {
    用外面ImagePipelineConfig 初始化final的config,不再变化,这个变量开发者 可自行配置
    mConfig = Preconditions.checkNotNull(config);
    mThreadHandoffProducerQueue = new ThreadHandoffProducerQueue(
        config.getExecutorSupplier().forLightweightBackgroundTasks());
  }

ImagePipelineFactory是图像管道的工厂类,这个类从其他库构造管道及其依赖关系。其目的是构造图像管道类ImagePipeline 。可以通过下面方法获取图像管道

  public ImagePipeline getImagePipeline() {
    if (mImagePipeline == null) {
      mImagePipeline =
          new ImagePipeline(
              getProducerSequenceFactory(),
              mConfig.getRequestListeners(),
              mConfig.getIsPrefetchEnabledSupplier(),
              getBitmapMemoryCache(),
              getEncodedMemoryCache(),
              getMainBufferedDiskCache(),
              getSmallImageBufferedDiskCache(),
              mConfig.getCacheKeyFactory(),
              mThreadHandoffProducerQueue,
              Suppliers.of(false));
    }
    return mImagePipeline;
  }

ImagePipelineFactory类中的所有变量都是通过ImagePipelineConfig的配置构造的。目的是为了构造出ImagePipeline对象

如果初始化时Config == null ,在ImagePipelineFactory中会初始化默认的ImagePipelineConfig配置

 /**
   * Initializes {@link ImagePipelineFactory} with default config.
   */
  public static void initialize(Context context) {
    initialize(ImagePipelineConfig.newBuilder(context).build());
  }

前面说了,ImagePipelineConfig类可以开发人员自行配置,只需要在builder模式下set项目需要改变的量,其他成员变量使用默认的即可。
ImagePipelineConfig是图像管道库的主配置类,

public class ImagePipelineConfig {

 // If a member here is marked @Nullable, it must be constructed by ImagePipelineFactory
 // on demand if needed.

 // There are a lot of parameters in this class. Please follow strict alphabetical order.
 private final Bitmap.Config mBitmapConfig;
 private final Supplier<MemoryCacheParams> mBitmapMemoryCacheParamsSupplier;
 private final CountingMemoryCache.CacheTrimStrategy mBitmapMemoryCacheTrimStrategy;
 private final CacheKeyFactory mCacheKeyFactory;
 private final Context mContext;
 private final boolean mDownsampleEnabled;
 private final FileCacheFactory mFileCacheFactory;
 private final Supplier<MemoryCacheParams> mEncodedMemoryCacheParamsSupplier;
 private final ExecutorSupplier mExecutorSupplier;
 private final ImageCacheStatsTracker mImageCacheStatsTracker;
 @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;
 @Nullable private final ImageDecoderConfig mImageDecoderConfig;
 private final ImagePipelineExperiments mImagePipelineExperiments;

 private static DefaultImageRequestConfig
     sDefaultImageRequestConfig = new DefaultImageRequestConfig();

 private ImagePipelineConfig(Builder builder) {
   // We have to build experiments before the rest
   mImagePipelineExperiments = builder.mExperimentsBuilder.build();
   mBitmapMemoryCacheParamsSupplier =
       builder.mBitmapMemoryCacheParamsSupplier == null ?
           new DefaultBitmapMemoryCacheParamsSupplier(
               (ActivityManager) builder.mContext.getSystemService(Context.ACTIVITY_SERVICE)) :
           builder.mBitmapMemoryCacheParamsSupplier;
   mBitmapMemoryCacheTrimStrategy =
       builder.mBitmapMemoryCacheTrimStrategy == null ?
           new BitmapMemoryCacheTrimStrategy() :
           builder.mBitmapMemoryCacheTrimStrategy;
   mBitmapConfig =
       builder.mBitmapConfig == null ?
           Bitmap.Config.ARGB_8888 :
           builder.mBitmapConfig;
   mCacheKeyFactory =
       builder.mCacheKeyFactory == null ?
           DefaultCacheKeyFactory.getInstance() :
           builder.mCacheKeyFactory;
   mContext = Preconditions.checkNotNull(builder.mContext);
   mFileCacheFactory = builder.mFileCacheFactory == null ?
       new DiskStorageCacheFactory(new DynamicDefaultDiskStorageFactory()) :
       builder.mFileCacheFactory;
   mDownsampleEnabled = builder.mDownsampleEnabled;
   mEncodedMemoryCacheParamsSupplier =
       builder.mEncodedMemoryCacheParamsSupplier == null ?
           new DefaultEncodedMemoryCacheParamsSupplier() :
           builder.mEncodedMemoryCacheParamsSupplier;
   mImageCacheStatsTracker =
       builder.mImageCacheStatsTracker == null ?
           NoOpImageCacheStatsTracker.getInstance() :
           builder.mImageCacheStatsTracker;
   mImageDecoder = builder.mImageDecoder;
   mIsPrefetchEnabledSupplier =
       builder.mIsPrefetchEnabledSupplier == null ?
           new Supplier<Boolean>() {
             @Override
             public Boolean get() {
               return true;
             }
           } :
           builder.mIsPrefetchEnabledSupplier;
   mMainDiskCacheConfig =
       builder.mMainDiskCacheConfig == null ?
           getDefaultMainDiskCacheConfig(builder.mContext) :
           builder.mMainDiskCacheConfig;
   mMemoryTrimmableRegistry =
       builder.mMemoryTrimmableRegistry == null ?
           NoOpMemoryTrimmableRegistry.getInstance() :
           builder.mMemoryTrimmableRegistry;
   mNetworkFetcher =
       builder.mNetworkFetcher == null ?
           new HttpUrlConnectionNetworkFetcher() :
           builder.mNetworkFetcher;
   mPlatformBitmapFactory = builder.mPlatformBitmapFactory;
   mPoolFactory =
       builder.mPoolFactory == null ?
           new PoolFactory(PoolConfig.newBuilder().build()) :
           builder.mPoolFactory;
   mProgressiveJpegConfig =
       builder.mProgressiveJpegConfig == null ?
           new SimpleProgressiveJpegConfig() :
           builder.mProgressiveJpegConfig;
   mRequestListeners =
       builder.mRequestListeners == null ?
           new HashSet<RequestListener>() :
           builder.mRequestListeners;
   mResizeAndRotateEnabledForNetwork = builder.mResizeAndRotateEnabledForNetwork;
   mSmallImageDiskCacheConfig =
       builder.mSmallImageDiskCacheConfig == null ?
           mMainDiskCacheConfig :
           builder.mSmallImageDiskCacheConfig;
   mImageDecoderConfig = builder.mImageDecoderConfig;
   // Below this comment can't be built in alphabetical order, because of dependencies
   int numCpuBoundThreads = mPoolFactory.getFlexByteArrayPoolMaxNumThreads();
   mExecutorSupplier =
       builder.mExecutorSupplier == null ?
           new DefaultExecutorSupplier(numCpuBoundThreads) : builder.mExecutorSupplier;
   // Here we manage the WebpBitmapFactory implementation if any
   WebpBitmapFactory webpBitmapFactory = mImagePipelineExperiments.getWebpBitmapFactory();
   if (webpBitmapFactory != null) {
     BitmapCreator bitmapCreator = new HoneycombBitmapCreator(getPoolFactory());
     setWebpBitmapFactory(webpBitmapFactory, mImagePipelineExperiments, bitmapCreator);
   } else {
     // We check using introspection only if the experiment is enabled
     if (mImagePipelineExperiments.isWebpSupportEnabled() &&
         WebpSupportStatus.sIsWebpSupportRequired) {
       webpBitmapFactory = WebpSupportStatus.loadWebpBitmapFactoryIfExists();
       if (webpBitmapFactory != null) {
         BitmapCreator bitmapCreator = new HoneycombBitmapCreator(getPoolFactory());
         setWebpBitmapFactory(webpBitmapFactory, mImagePipelineExperiments, bitmapCreator);
       }
     }
   }
 }

ImagePipelineConfig.newBuilderm看出ImagePipelineConfig的成员变量,有这么多。

  public static class Builder {
    Bitmap配置 565或者8888
    private Bitmap.Config mBitmapConfig;
    内存缓存参数提供者
    private Supplier<MemoryCacheParams> mBitmapMemoryCacheParamsSupplier;
    private CountingMemoryCache.CacheTrimStrategy mBitmapMemoryCacheTrimStrategy;
    缓存Key工厂
    private CacheKeyFactory mCacheKeyFactory;
    private final Context mContext;
    是否下采样
    private boolean mDownsampleEnabled = false;
    编码内存缓存提供者
    private Supplier<MemoryCacheParams> mEncodedMemoryCacheParamsSupplier;
    private ExecutorSupplier mExecutorSupplier;
    private ImageCacheStatsTracker mImageCacheStatsTracker;
    图片解码器
    private ImageDecoder mImageDecoder;
    private Supplier<Boolean> mIsPrefetchEnabledSupplier;
    磁盘缓存注册表
    private DiskCacheConfig mMainDiskCacheConfig;
    内存可修改注册表
    private MemoryTrimmableRegistry mMemoryTrimmableRegistry;
    private NetworkFetcher mNetworkFetcher;
    private PlatformBitmapFactory mPlatformBitmapFactory;
    private PoolFactory mPoolFactory;
    private ProgressiveJpegConfig mProgressiveJpegConfig;
    private Set<RequestListener> mRequestListeners;
    private boolean mResizeAndRotateEnabledForNetwork = true;
    小图片磁盘缓存配置
    private DiskCacheConfig mSmallImageDiskCacheConfig;
    private FileCacheFactory mFileCacheFactory;
    图片解码配置
    private ImageDecoderConfig mImageDecoderConfig;
    private final ImagePipelineExperiments.Builder mExperimentsBuilder
        = new ImagePipelineExperiments.Builder(this);

项目中用到的ImagePipelineConfig。

package com.sohu.ink;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;

import com.facebook.cache.disk.DiskCacheConfig;
import com.facebook.common.disk.NoOpDiskTrimmableRegistry;
import com.facebook.common.internal.Supplier;
import com.facebook.common.memory.MemoryTrimType;
import com.facebook.common.memory.MemoryTrimmable;
import com.facebook.common.memory.NoOpMemoryTrimmableRegistry;
import com.facebook.common.util.ByteConstants;
import com.facebook.imagepipeline.cache.MemoryCacheParams;
import com.facebook.imagepipeline.core.ImagePipelineConfig;
import com.facebook.imagepipeline.core.ImagePipelineFactory;

/**
 * <p/>
 * 功能 :
 * <p/>
 * <p>
 * <p>Copyright sohu.com 2017 All right reserved</p>
 *
 * @author ketu 时间 2017/11/22
 * @version 2.0
 *          <p>
 *          最后修改人 无
 * @email ketu@sohu-inc.com
 * @link {http://blog.csdn.net/biezhihua/article/details/49893323,
 * http://blog.csdn.net/honjane/article/details/65629799}
 */

public class ImagePipelineConfigUtils {
    //分配的可用内存
    public static final int MAX_HEAP_SIZE = (int) Runtime.getRuntime().maxMemory();

    //使用的缓存数量
    public static final int MAX_MEMORY_CACHE_SIZE = MAX_HEAP_SIZE / 4;

    //小图极低磁盘空间缓存的最大值(特性:可将大量的小图放到额外放在另一个磁盘空间防止大图占用磁盘空间而删除了大量的小图)
    public static final int MAX_SMALL_DISK_VERYLOW_CACHE_SIZE = 20 * ByteConstants.MB;

    //小图低磁盘空间缓存的最大值(特性:可将大量的小图放到额外放在另一个磁盘空间防止大图占用磁盘空间而删除了大量的小图)
    public static final int MAX_SMALL_DISK_LOW_CACHE_SIZE = 60 * ByteConstants.MB;

    //默认图极低磁盘空间缓存的最大值
    public static final int MAX_DISK_CACHE_VERYLOW_SIZE = 20 * ByteConstants.MB;

    //默认图低磁盘空间缓存的最大值
    public static final int MAX_DISK_CACHE_LOW_SIZE = 60 * ByteConstants.MB;

    //默认图磁盘缓存的最大值
    public static final int MAX_DISK_CACHE_SIZE = 100 * ByteConstants.MB;


    //小图所放路径的文件夹名
    public static final String IMAGE_PIPELINE_SMALL_CACHE_DIR = "ImagePipelineCacheSmall";

    //默认图所放路径的文件夹名
    public static final String IMAGE_PIPELINE_CACHE_DIR = "ImagePipelineCacheDefault";

    //内存配置
    public static final int MAX_CACHE_ENTRIES = 56;
    public static final int MAX_CACHE_ASHM_ENTRIES = 128;
    public static final int MAX_CACHE_EVICTION_SIZE = 30;//30M,越小,gc越频繁,越卡,合理设置此项,含义是:被fresco标记为回收的大小积累到这个值就会gc
    public static final int MAX_CACHE_EVICTION_ENTRIES = 5;


    public static ImagePipelineConfig getDefaultImagePipelineConfig(Context context) {

        //内存配置
        final MemoryCacheParams bitmapCacheParams = new MemoryCacheParams(
                MAX_MEMORY_CACHE_SIZE,// 内存缓存中总图片的最大大小,以字节为单位。
                Integer.MAX_VALUE,// 内存缓存中图片的最大数量。
                MAX_MEMORY_CACHE_SIZE,// 内存缓存中准备清除但尚未被删除的总图片的最大大小,以字节为单位。
                Integer.MAX_VALUE,// 内存缓存中准备清除的总图片的最大数量。
                Integer.MAX_VALUE);// 内存缓存中单个图片的最大大小。

        //修改内存图片缓存数量,空间策略(这个方式有点恶心)
        Supplier<MemoryCacheParams> mSupplierMemoryCacheParams = new Supplier<MemoryCacheParams>() {
            @Override
            public MemoryCacheParams get() {
                //return bitmapCacheParams;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    return new MemoryCacheParams(MAX_MEMORY_CACHE_SIZE, MAX_CACHE_ENTRIES, MAX_CACHE_EVICTION_SIZE, MAX_CACHE_EVICTION_ENTRIES, 1);
                } else {
                    return new MemoryCacheParams(
                            MAX_MEMORY_CACHE_SIZE,
                            MAX_CACHE_ASHM_ENTRIES,
                            Integer.MAX_VALUE,
                            Integer.MAX_VALUE,
                            Integer.MAX_VALUE);
                }
            }
        };

        //小图片的磁盘配置
        DiskCacheConfig diskSmallCacheConfig = DiskCacheConfig.newBuilder(context)
                .setBaseDirectoryPath(context.getApplicationContext().getCacheDir())//缓存图片基路径
                .setBaseDirectoryName(IMAGE_PIPELINE_SMALL_CACHE_DIR)//文件夹名
                .setMaxCacheSize(MAX_DISK_CACHE_SIZE)//默认缓存的最大大小。
                .setMaxCacheSizeOnLowDiskSpace(MAX_SMALL_DISK_LOW_CACHE_SIZE)//缓存的最大大小,使用设备时低磁盘空间。
                .setMaxCacheSizeOnVeryLowDiskSpace(MAX_SMALL_DISK_VERYLOW_CACHE_SIZE)//缓存的最大大小,当设备极低磁盘空间
                .setDiskTrimmableRegistry(NoOpDiskTrimmableRegistry.getInstance())
                .build();

        //默认图片的磁盘配置
        DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder(context)
                .setBaseDirectoryPath(context.getApplicationContext().getCacheDir())//缓存图片基路径,,Environment.getExternalStorageDirectory().getAbsoluteFile()
                .setBaseDirectoryName(IMAGE_PIPELINE_CACHE_DIR)//文件夹名
                .setMaxCacheSize(MAX_DISK_CACHE_SIZE)//默认缓存的最大大小。
                .setMaxCacheSizeOnLowDiskSpace(MAX_DISK_CACHE_LOW_SIZE)//缓存的最大大小,使用设备时低磁盘空间。
                .setMaxCacheSizeOnVeryLowDiskSpace(MAX_DISK_CACHE_VERYLOW_SIZE)//缓存的最大大小,当设备极低磁盘空间
                .setDiskTrimmableRegistry(NoOpDiskTrimmableRegistry.getInstance())
                .build();


        // 就是这段代码,用于清理缓存
        NoOpMemoryTrimmableRegistry.getInstance().registerMemoryTrimmable(new MemoryTrimmable() {
            @Override
            public void trim(MemoryTrimType trimType) {
                final double suggestedTrimRatio = trimType.getSuggestedTrimRatio();

                //Loger.d(String.format("onCreate suggestedTrimRatio : %d", suggestedTrimRatio));
                if (MemoryTrimType.OnCloseToDalvikHeapLimit.getSuggestedTrimRatio() == suggestedTrimRatio
                        || MemoryTrimType.OnSystemLowMemoryWhileAppInBackground.getSuggestedTrimRatio() == suggestedTrimRatio
                        || MemoryTrimType.OnSystemLowMemoryWhileAppInForeground.getSuggestedTrimRatio() == suggestedTrimRatio
                        ) {
                    ImagePipelineFactory.getInstance().getImagePipeline().clearMemoryCaches();
                }
            }
        });

        //最终缓存图片配置
        ImagePipelineConfig.Builder configBuilder = ImagePipelineConfig.newBuilder(context)
                .setBitmapsConfig(Bitmap.Config.ARGB_8888)
                .setBitmapMemoryCacheParamsSupplier(mSupplierMemoryCacheParams)
                .setSmallImageDiskCacheConfig(diskSmallCacheConfig)
                .setMainDiskCacheConfig(diskCacheConfig)
                .setMemoryTrimmableRegistry(NoOpMemoryTrimmableRegistry.getInstance())
                .setResizeAndRotateEnabledForNetwork(true)
                .setDownsampleEnabled(true);//设置下采样,适应png,webp


        return configBuilder.build();
    }
}

初始化Drawee模块

在Frseco.initize()代码中

  /** Initializes Drawee with the specified config. */
  private static void initializeDrawee(
      Context context,
      @Nullable DraweeConfig draweeConfig) {
    sDraweeControllerBuilderSupplier =
        new PipelineDraweeControllerBuilderSupplier(context, draweeConfig);
    SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier);
  }

实际上主要是构造出SimpleDraweeView的DraweeController变量。
在了解之前先看看

  sDraweeControllerBuilderSupplier =
        new PipelineDraweeControllerBuilderSupplier(context, draweeConfig);

DraweeController是怎么生成的。

上一篇下一篇

猜你喜欢

热点阅读