簡介
以下是官網對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;
}
到這裏初始化就結束了。看着代碼不多,其實在新建各個組建的時候還是做了很多事情的,比如根據不同的平臺初始化不同的對象。下一篇文章我們就從頭開始,更細緻的看一下各個組建的創建過程。