Fresco源码解析 - 初始化过程分析

使用Fresco之前,一定先要进行初始化,一般初始化的工作会在Application.onCreate()完成,当然也可以在使用Drawee之前完成。

Fresco本身提供了两种初始化方式,一种是使用使用默认配置初始化,另一种是使用用户自定义配置。

如下代码是Fresco提供的两个初始化方法。第一个只需要提供一个Context参数,第二个还需要提供 ImagePipeline 的配置实例 - ImagePipelineConfig

/** Initializes Fresco with the default config. */
public static void initialize(Context context) {
  ImagePipelineFactory.initialize(context);
  initializeDrawee(context);
}
/** Initializes Fresco with the specified config. */
public static void initialize(Context context, ImagePipelineConfig imagePipelineConfig) {
  ImagePipelineFactory.initialize(imagePipelineConfig);
  initializeDrawee(context);
}


先来分析一下第一种方式。

开始初始化

Fresco.initialized(context)

使用默认参数进行初始化

com.facebook.drawee.backends.pipeline.Fresco

/** Initializes Fresco with the default config. */
public static void initialize(Context context) {
    ImagePipelineFactory.initialize(context);
    initializeDrawee(context);
}

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

创建 ImagePipeline

com.facebook.imagepipeline.core.ImagePipelineFactory

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

ImagePipelineConfigImagePipeline的初始化工作提供了必需的参数,它的构建过程采用了Builder模式

ImagePipelineConfig 中包含了很多参数,因为我们调用 Fresco.initialize()的时候值传递了一个 context 参数,所以 Fresco 还没有获取任何用户自定义的数据,因此全部使用默认值,Builder 类只提供了构建的过程,而默认值则需要等到新建 ImagePipelineConfig时创建。

通过 Builder 的部分源码可以看出,初始化一个 ImagePipeline 需要很多参数,这些参数的具体意义会在后续的博文中介绍。

public static class Builder {
  private Supplier<MemoryCacheParams> mBitmapMemoryCacheParamsSupplier;
  private CacheKeyFactory mCacheKeyFactory;
  private final Context mContext;
  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 PoolFactory mPoolFactory;
  private ProgressiveJpegConfig mProgressiveJpegConfig;
  private Set<RequestListener> mRequestListeners;
  private boolean mResizeAndRotateEnabledForNetwork = true;
  private DiskCacheConfig mSmallImageDiskCacheConfig;
  private AnimatedImageFactory mAnimatedImageFactory;

  // other methods
}

从 Fresco 的 initialize 方法中我们得知,ImagePipelineConfig 是这么创建的:

ImagePipelineConfig.newBuilder(context).build())

Builder 并没有提供参数的默认值,那默认值肯定是在 buid() 方法完成赋值。

com.facebook.imagepipeline.core.ImagePipelineFactory$Builder

public ImagePipelineConfig build() {
  return new ImagePipelineConfig(this);
}

由以上代码可以看出,build()会创建一个 ImagePipelineConfig ,然后把 this 作为参数传给构造函数,而ImagePipelineConfig 的构造函数就是根据 Builder 来初始化自己。

初始化的策略非常简单:

  • 如果 builder 中的参数值为空,则使用默认值。
  • 如果 builder 中的参数值不为空,则使用 Builder 提供的值。

可以通过一个具体的参数来看一下,如果 builder.mBitmapMemoryCacheParamsSupplier 为空,则 new DefaultBitmapMemoryCacheParamsSupplier(),如果不空,则使用 builder.mBitmapMemoryCacheParamsSupplier

mBitmapMemoryCacheParamsSupplier =
    builder.mBitmapMemoryCacheParamsSupplier == null ?
        new DefaultBitmapMemoryCacheParamsSupplier(
            (ActivityManager) builder.mContext.getSystemService(Context.ACTIVITY_SERVICE)) :
        builder.mBitmapMemoryCacheParamsSupplier;

最后把这个 build 出来的 ImagePipelineConfig 实例传给 ImagePipelineFactory 的静态方法 initialize,完成初始化。

/** Initializes {@link ImagePipelineFactory} with the specified config. */
public static void initialize(ImagePipelineConfig imagePipelineConfig) {
  sInstance = new ImagePipelineFactory(imagePipelineConfig);
}

ImagePipelineFactory 的实例 sInstance 会在初始化 Drawee 的时候用到。

初始化 Drawee

通过以上分析我们了解到,Fresco 会首先初始化 ImagePipeline,并把ImagePipeline 的实例保存在一个 ImagePipelineFactory 类型的静态变量中 - sInstance;然后开始初始化 Drawee

private static void initializeDrawee(Context context) {
  sDraweeControllerBuilderSupplier = new PipelineDraweeControllerBuilderSupplier(context);
  SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier);
}

首先,new 一个 PipelineDraweeControllerBuilderSupplier,它是 PipelineDraweeControllerBuilder 的一个 SupplierSupplier不是由 JDK 提供的,而是 Fresco 直接从 guava 中移过来的,代码简单,只提供了一个 get 方法。

/**
 * A class that can supply objects of a single type.  Semantically, this could
 * be a factory, generator, builder, closure, or something else entirely. No
 * guarantees are implied by this interface.
 *
 * @author Harry Heymann
 * @since 2.0 (imported from Google Collections Library)
 */
public interface Supplier<T> {
  /**
   * Retrieves an instance of the appropriate type. The returned object may or
   * may not be a new instance, depending on the implementation.
   *
   * @return an instance of the appropriate type
   */
  T get();
}

顾名思义,Supplier 是一个提供者,用户包括但不限于factory, generator, builder, closure,接口方法 get() 用于返回它所提供的实例,需要注意的是,这个实例可以是新建的,也可以不是。

在这里,PipelineDraweeControllerBuilderSupplier 的用法更像是一个 Factory,它实现了 Supplier 接口。

public class PipelineDraweeControllerBuilderSupplier implements
    Supplier<PipelineDraweeControllerBuilder> {

  private final Context mContext;
  private final ImagePipeline mImagePipeline;
  private final PipelineDraweeControllerFactory mPipelineDraweeControllerFactory;
  private final Set<ControllerListener> mBoundControllerListeners;

  public PipelineDraweeControllerBuilderSupplier(Context context) {
    this(context, ImagePipelineFactory.getInstance());
  }

  public PipelineDraweeControllerBuilderSupplier(
      Context context,
      ImagePipelineFactory imagePipelineFactory) {
    this(context, imagePipelineFactory, null);
  }

  public PipelineDraweeControllerBuilderSupplier(
      Context context,
      ImagePipelineFactory imagePipelineFactory,
      Set<ControllerListener> boundControllerListeners) {
    mContext = context;
    mImagePipeline = imagePipelineFactory.getImagePipeline();
    mPipelineDraweeControllerFactory = new PipelineDraweeControllerFactory(
        context.getResources(),
        DeferredReleaser.getInstance(),
        imagePipelineFactory.getAnimatedDrawableFactory(),
        UiThreadImmediateExecutorService.getInstance());
    mBoundControllerListeners = boundControllerListeners;
  }

  @Override
  public PipelineDraweeControllerBuilder get() {
    return new PipelineDraweeControllerBuilder(
        mContext,
        mPipelineDraweeControllerFactory,
        mImagePipeline,
        mBoundControllerListeners);
  }
}

构造函数 PipelineDraweeControllerBuilderSupplier(Context context),使用了在 Frescoinitalize 方法中通过 ImagePipelineFactoryBuilder 创建的 ImagePipelineFactory 的实例。

this(context, ImagePipelineFactory.getInstance());

get 方法告诉我们,ImagePipeline 会存储在 PipelineDraweeController 中,关于 Controller 可以参考 Fresco源码解析 - Hierarachy-View-Controller

同时 PipelineDraweeController 也会存储一个 mPipelineDraweeControllerFactory

public class PipelineDraweeControllerFactory {

  private Resources mResources;
  private DeferredReleaser mDeferredReleaser;
  private AnimatedDrawableFactory mAnimatedDrawableFactory;
  private Executor mUiThreadExecutor;

  public PipelineDraweeControllerFactory(
      Resources resources,
      DeferredReleaser deferredReleaser,
      AnimatedDrawableFactory animatedDrawableFactory,
      Executor uiThreadExecutor) {
    mResources = resources;
    mDeferredReleaser = deferredReleaser;
    mAnimatedDrawableFactory = animatedDrawableFactory;
    mUiThreadExecutor = uiThreadExecutor;
  }

  public PipelineDraweeController newController(
      Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier,
      String id,
      Object callerContext) {
    return new PipelineDraweeController(
        mResources,
        mDeferredReleaser,
        mAnimatedDrawableFactory,
        mUiThreadExecutor,
        dataSourceSupplier,
        id,
        callerContext);
  }
}

这个 mPipelineDraweeControllerFactory 会通过 newController 来创建一个 PipelineDraweeController 的实例。

到底,初始化的工作就完成了。



以上分析虽然简单,但是清楚地梳理了 Fresco 的初始化过程,不过任然是远远不够的,由以上代码可以看出,初始化对应组件(Drawee、ImagePipeline)时用到了很多的设计模式,如果不太熟悉这些设计模式,可能理解起来会比较吃力。更加关键的是,初始化对应的组件用到了大量的参数,每个参数背后又会牵扯到很多知识点,后续博文中,我们再来一一分析。

时间: 2024-12-13 22:44:18

Fresco源码解析 - 初始化过程分析的相关文章

Fresco源码解析 - 创建一个ImagePipeline(一)

在Fresco源码解析 - 初始化过程分析章节中,我们分析了Fresco的初始化过程,两个initialize方法中都用到了 ImagePipelineFactory类. ImagePipelineFactory.initialize(context);会创建一个所有参数都使用默认值的ImagePipelineConfig来初始化ImagePipeline. ImagePipelineFactory.initialize(imagePipelineConfig)会首先用 imagePipelin

Fresco源码解析 - 本地编译

第一次写专栏,如有表述不好或者理解错误的地方,请各位读者不吝赐教,本人一定虚心接受并第一时间改正. 作为专题第一篇,先从最简单的开始,顺便找找感觉. Fresco 是 facebook 在今年的 F8 大会上宣布开源的一个用于加载图片的库,它不仅支持多种图片文件格式,而且由于使用了pinned purgeables 技术,使得大图加载过程中产生OOM的概率大大降低,对开发者来说绝对是一件喜大普奔的事情,对于像天猫HD这样需要加载大量图片的APP来说也绝对是个福音. 下载代码 首先把源码从 Git

springmvc源码解析-初始化

1.      概述 对于Web开发者,MVC模型是大家再熟悉不过的了,SpringMVC中,满足条件的请求进入到负责请求分发的DispatcherServlet,DispatcherServlet根据请求url到控制器的映射(HandlerMapping中保存),HandlerMapping最终返回HandlerExecutionChain,其中包含了具体的处理对象handler(也即我们编程时写的controller)以及一系列的拦截器interceptors,此时DispatcherSer

Tomcat源码解析-启动过程分析之主干流程

Tomcat启动入口就在脚本startup.sh中,具体脚本可以看tomcat的源码,这个启动脚本主要用来判断环境,找到catalina.sh脚本路径,将启动参数传递给catalina.sh执行.catalina.sh start 最终会执行org.apache.catalina.startup.Bootstrap中的main方法,并把start参数传入.以后分析Tomcat关闭的时候,也是一个套路,最终都会调用到org.apache.catalina.startup.Bootstrap的mai

Fresco源码解析 - DraweeView

DraweeView 是Fresco的三大组件(Hierarchy.Controller.View) 之一,作为MVC模式中的 View,主要负责显示由 Hierarchy 提供的数据(placeholder.actual image.progress drawable等),Controller 作为幕后,负责获取数据. 继承体系 DraweeView 并不是是一个简单的自定义View,它必须要提供与 Hierarchy 和 Controller 交互的接口,DraweeView 的继承关系如下

Fresco源码解析 - DataSource怎样存储数据

datasource是一个独立的 package,与FB导入的guava包都在同一个工程内 - fbcore. datasource的类关系比较简单,一张类图基本就可以描述清楚它们间的关系. DataSource 是一个 interface, 功能与JDK中的Future类似,但是相比于Future,它的先进之处则在于 不仅仅只生产一个单一的结果,而是能够提供系列结果. Unlike Futures, DataSource can issue a series of results, rathe

Fresco 源码解析 - 利用 @DoNotSkip 来防止混淆

我们都知道,如果打开了混淆开关,代码 release 阶段会根据 proguard 规则进行混淆,但是有些实体类(例如 json 字符串对应的 model)需要进行序列化.反序列化,而序列化工具(例如 Gson.fastjson)是利用反射来一一对应 json 串的 key 和实体类的成员变量. 例如,我们定义一个 POJO 类型的 User 实体类: public class User { public String firstName; public String lastName; pub

Fresco源码解析 - Hierarachy-View-Controller

Fresco是一个MVC模型,由三大组件构成,它们的对应关系如下所示: M -> DraweeHierarchy V -> DraweeView C -> DraweeController M 所对应的 DraweeHierarchy 是一个有层次结构的数据结构,DraweeView 用来显示位于 DraweeHierarchy 最顶层的图像(top level drawable),DraweeController 则用来控制 DraweeHierarchy 的顶层图像是哪一个. o F

LinkedList原理及源码解析

简介 LinkedList是一个双向线性链表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer).由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1). UML关系图 使用示例 LinkedList list = new LinkedList<>(); //新增 list.add("a"