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