Fresco源码解析: 初始化过程(一)

简介

以下是官网对fresco的定义:
fresco是一款功能强大的图片加载工具,使用它之后,你不必再去关心图片的加载和显示这些繁琐的事情!支持Android2.1及以后的版本。
中文官网地址如下:https://www.fresco-cn.org/,代码下载地址:git clone https://github.com/facebook/fresco.git

特性

内存管理

在5.0以下系统,Fresco将图片放到一个特别的内存区域。当然,在图片不显示的时候,占用的内存会自动被释放。这会使得APP更加流畅,减少因图片内存占用而引发的OOM。

图片加载

支持WebP解码,即使在早先对WebP支持不完善的Android系统上也能正常使用!

图片的渐进式呈现

Android 本身的图片库不支持此格式,但是Fresco支持。使用时,和往常一样,仅仅需要提供一个图片的URI即可,剩下的事情,Fresco会处理。

动图加载

加载Gif图和WebP动图在任何一个Android开发者眼里看来都是一件非常头疼的事情。每一帧都是一张很大的Bitmap,每一个动画都有很多帧。Fresco让你没有这些烦恼,它处理好每一帧并管理好你的内存。

以上是copy官网的内容。好,废话不多讲,下面开始源码解析。这篇博客主要讲Fresco的初始化,在后面的博客中随着本人的研究,会慢慢深入。

Fresco的初始化

官网的示例代码如下

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Fresco.initialize(this);
    }
}

所以就从Fresco.initialize(this)开始看,Fresco的java文件路径如下:

fresco\drawee-backends\drawee-pipeline\src\main\java\com\facebook\drawee\backends\pipeline\Fresco.java

initialize方法的代码如下:

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

可以看到最终是调用了

public static void initialize(Context context,@Nullable ImagePipelineConfigimagePipelineConfig,
@Nullable DraweeConfig draweeConfig)
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
    context = context.getApplicationContext();
    if (imagePipelineConfig == null) {
      ImagePipelineFactory.initialize(context);
    } else {
      ImagePipelineFactory.initialize(imagePipelineConfig);
    }
    initializeDrawee(context, draweeConfig);
  }

可以看到,如果已经被初始化过的话就直接返回。因为我们是直接调用的Fresco.initialize(this),并没有指定imagePipelineConfig,所以走到ImagePipelineFactory.initialize(context),这个方法是初始化ImagePipelineFactory的,后面用到的ImagePipeline就是有这个类产生。方法源码如下:

  public static void initialize(Context context) {
    initialize(ImagePipelineConfig.newBuilder(context).build());
  }

此方法中新建了一个ImagePipelineConfig,这个对象很重要,因为后面加载图片用到的基本所有组件都是这里指定。我们来具体看一下里面的内容,通过跟踪code,发现最终是调用了ImagePipelineConfig的构造方法

 private ImagePipelineConfig(Builder builder) {
    // We have to build experiments before the rest
    //目前处于实验状态的一些选项,变动很大,官方建议不要修改这些选项的默认值
    mImagePipelineExperiments = builder.mExperimentsBuilder.build();
    //bitmap内存缓存参数的提供者,以MemoryCacheParams类的形式封装
    mBitmapMemoryCacheParamsSupplier = builder.mBitmapMemoryCacheParamsSupplier == null ?
            new DefaultBitmapMemoryCacheParamsSupplier((ActivityManager) builder.mContext.getSystemService(Context.ACTIVITY_SERVICE)) :
            builder.mBitmapMemoryCacheParamsSupplier;
    //内存回收策略
    mBitmapMemoryCacheTrimStrategy = builder.mBitmapMemoryCacheTrimStrategy == null ? new BitmapMemoryCacheTrimStrategy() :
            builder.mBitmapMemoryCacheTrimStrategy;
   // bitmap的配置参数,Bitmap.Config默认使用ARGB_8888,相对于Glid更好内存
    mBitmapConfig = builder.mBitmapConfig == null ? Bitmap.Config.ARGB_8888 : builder.mBitmapConfig;
    //生成缓存key的工厂,如果不想使用默认的key生成方法,可以自定义这个factory
    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;
     //网络数据获取的工具,默认使用HttpUrlConnectionNetworkFetcher,也可以自己定义
    mNetworkFetcher = builder.mNetworkFetcher == null ?  new HttpUrlConnectionNetworkFetcher() : builder.mNetworkFetcher;
    //根据不同android版本生成不同的bitmap的工厂,主要是bitmap内存存储位置,5.0以前存储在ashmem,5.0以后存在java heap中
    mPlatformBitmapFactory = builder.mPlatformBitmapFactory;
    //生产各种池的工厂
    mPoolFactory = builder.mPoolFactory == null ? new PoolFactory(PoolConfig.newBuilder().build()) : builder.mPoolFactory;
    //渐进式加载的配置参数
    mProgressiveJpegConfig = builder.mProgressiveJpegConfig == null ? new SimpleProgressiveJpegConfig() :builder.mProgressiveJpegConfig;
    //监听request过程中的各种事件
    mRequestListeners = builder.mRequestListeners == null ? new HashSet<RequestListener>() : builder.mRequestListeners;
    mResizeAndRotateEnabledForNetwork = builder.mResizeAndRotateEnabledForNetwork;
    //小图硬盘缓存的配置参数,对应于mMainDiskCacheConfig 
    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
    //在不支持webp的android版本上(4.0开始支持简单的webp,4.2.1后全面支持)支持解码webp图片的工厂,默认为null
    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);
        }
      }
    }
  }

各个选项的意思我已经在代码中注释,后面的文章中还会继续详细说明这些选项。现在回到Fresco.initialize方法,在完成ImagePipelineFactory的初始化后,就开始Drawee的初始化

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
    context = context.getApplicationContext();
    if (imagePipelineConfig == null) {
      ImagePipelineFactory.initialize(context);
    } else {
      ImagePipelineFactory.initialize(imagePipelineConfig);
    }
    initializeDrawee(context, draweeConfig);
  }

initializeDrawee(context, draweeConfig)方法的代码如下:

  private static void initializeDrawee(Context context,@Nullable DraweeConfig draweeConfig) {
    sDraweeControllerBuilderSupplier = new PipelineDraweeControllerBuilderSupplier(context, draweeConfig);
    SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier);
  }

可以看到先是new了一个PipelineDraweeControllerBuilderSupplier对象,在Fresco的源码中你会看到很多类都以Supplier结尾,其实这些类都是实现了Supplier接口,该接口只有一个get()方法,作用就是提供一个特定类型的对象。所以PipelineDraweeControllerBuilderSupplier从名字就可以看出这个对象是用于提供PipelineDraweeControllerBuilder的,而PipelineDraweeControllerBuilder类的作用就是用于创建PipelineDraweeController,PipelineDraweeController的作用就是连接imagePipeline和 SettableDraweeHierarchy的桥梁,具体怎样工作在后面的文章再说明。继续看PipelineDraweeControllerBuilderSupplier(context, draweeConfig)构造方法,最后是调到了

  public PipelineDraweeControllerBuilderSupplier(
      Context context,
      ImagePipelineFactory imagePipelineFactory,
      Set<ControllerListener> boundControllerListeners,
      @Nullable DraweeConfig draweeConfig) {
    mContext = context;
    mImagePipeline = imagePipelineFactory.getImagePipeline();

    if (draweeConfig != null && draweeConfig.getPipelineDraweeControllerFactory() != null) {
      mPipelineDraweeControllerFactory = draweeConfig.getPipelineDraweeControllerFactory();
    } else {
      mPipelineDraweeControllerFactory = new PipelineDraweeControllerFactory();
    }
    mPipelineDraweeControllerFactory.init(
        context.getResources(),
        DeferredReleaser.getInstance(),
        imagePipelineFactory.getAnimatedDrawableFactory(context),
        UiThreadImmediateExecutorService.getInstance(),
        mImagePipeline.getBitmapMemoryCache(),
        draweeConfig != null
            ? draweeConfig.getCustomDrawableFactories()
            : null,
        draweeConfig != null
            ? draweeConfig.getDebugOverlayEnabledSupplier()
            : null);
    mBoundControllerListeners = boundControllerListeners;
  }

这个构造函数主要工作是new了一个PipelineDraweeControllerFactory对象,并初始化这个对象,在初始化过程中又实例化了很多必要组件,这个文章后面再讲。PipelineDraweeControllerFactory是真正生产PipelineDraweeController的类,PipelineDraweeControllerBuilder只是对已有的PipelineDraweeController对象进行包装。
在new 完PipelineDraweeControllerBuilderSupplier后,又调用了SimpleDraweeView.initialize()其实就是将PipelineDraweeControllerBuilderSupplier对象赋值给SimpeDraweeView的sDraweeControllerBuilderSupplier变量。

  public static void initialize(
      Supplier<? extends SimpleDraweeControllerBuilder> draweeControllerBuilderSupplier) {
    sDraweeControllerBuilderSupplier = draweeControllerBuilderSupplier;
  }

到这里初始化就结束了。看着代码不多,其实在新建各个组建的时候还是做了很多事情的,比如根据不同的平台初始化不同的对象。下一篇文章我们就从头开始,更细致的看一下各个组建的创建过程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值