天天看點

fackbook的Fresco的Image Pipeline以及自身的緩存機制

fackbook的Fresco的Image Pipeline以及自身的緩存機制

配置之前、首先需要知道兩點:一點是Bitmap緩存、一點是如果你僅僅需要一個緩存,那麼不調用setSmallImageDiskCacheConfig即可。Image pipeline 預設會使用同一個緩存,同時ImageType也會被忽略。

配置Image Pipeline

對于大多數的應用,Fresco的初始化,隻需要以下一句代碼:

Fresco.initialize(context);      

對于那些需要更多進一步配置的應用,我們提供了ImagePipelineConfig。

以下是一個示例配置,列出了所有可配置的選項。幾乎沒有應用是需要以下這所有的配置的,列出來僅僅是為了作為參考。

ImagePipelineConfig config = ImagePipelineConfig.newBuilder()
    .setBitmapMemoryCacheParamsSupplier(bitmapCacheParamsSupplier)
    .setCacheKeyFactory(cacheKeyFactory)
    .setEncodedMemoryCacheParamsSupplier(encodedCacheParamsSupplier)
    .setExecutorSupplier(executorSupplier)
    .setImageCacheStatsTracker(imageCacheStatsTracker)
    .setMainDiskCacheConfig(mainDiskCacheConfig)
    .setMemoryTrimmableRegistry(memoryTrimmableRegistry) 
    .setNetworkFetchProducer(networkFetchProducer)
    .setPoolFactory(poolFactory)
    .setProgressiveJpegConfig(progressiveJpegConfig)
    .setRequestListeners(requestListeners)
    .setSmallImageDiskCacheConfig(smallImageDiskCacheConfig)
    .build();
Fresco.initialize(context, config);      

請記得将配置好的​

​ImagePipelineConfig​

​ 傳遞給 ​

​Fresco.initialize!​

​ 否則仍舊是預設配置。

關于Supplier

許多配置的Builder都接受一個Supplier 類型的參數而不是一個配置的執行個體。

建立時也許有一些麻煩,但這帶來更多的利好:這允許在運作時改變建立行為。以記憶體緩存為例,每隔5分鐘就可檢查一下Supplier,根據實際情況傳回不同類型。

如果你需要動态改變參數,那就是用Supplier每次都傳回同一個對象。

Supplier<X> xSupplier = new Supplier<X>() {
  public X get() {
    return new X(xparam1, xparam2...);
  }
);
// when creating image pipeline
.setXSupplier(xSupplier);      

線程池

Image pipeline 預設有3個線程池:(重要的事情要說三遍、三個線程池、三個線程池、是真的三個線程池)

  1. 3個線程用于網絡下載下傳
  2. 兩個線程用于磁盤操作: 本地檔案的讀取,磁盤緩存操作。
  3. 兩個線程用于CPU相關的操作: 解碼,轉換,以及後處理等背景操作。

對于網絡下載下傳,你可以定制網絡層的操作,具體參考:自定義網絡層加載.

對于其他操作,如果要改變他們的行為,傳入一個ExecutorSupplier即可。

記憶體緩存的配置

記憶體緩存和未解碼的記憶體緩存的配置由一個Supplier控制,這個Supplier傳回一個[MemoryCacheParams](../javadoc/reference/com/facebook/imagepipeline/cache/MemoryCacheParams.html#MemoryCacheParams(int, int, int, int, int)) 對象用于記憶體狀态控制。

配置磁盤緩存

你可使用Builder模式建立一個 DiskCacheConfig:

DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder()
   .set....
   .set....
   .build()

// when building ImagePipelineConfig
.setMainDiskCacheConfig(diskCacheConfig)      

緩存統計

如果你想統計緩存的命中率,你可以實作ImageCacheStatsTracker, 在這個類中,每個緩存時間都有回調通知,基于這些事件,可以實作緩存的計數和統計。

緩存

三級緩存

1. Bitmap緩存

Bitmap緩存存儲​

​Bitmap​

​對象,這些Bitmap對象可以立刻用來顯示或者用于後處理

在5.0以下系統,Bitmap緩存位于ashmem,這樣Bitmap對象的建立和釋放将不會引發GC,更少的GC會使你的APP運作得更加流暢。

5.0及其以上系統,相比之下,記憶體管理有了很大改進,是以Bitmap緩存直接位于Java的heap上。

當應用在背景運作是,該記憶體會被清空。

2. 未解碼圖檔的記憶體緩存

這個緩存存儲的是原始壓縮格式的圖檔。從該緩存取到的圖檔在使用之前,需要先進行解碼。

如果有調整大小,旋轉,或者WebP編碼轉換工作需要完成,這些工作會在解碼之前進行。

APP在背景時,這個緩存同樣會被清空。其實有一點很重要、你無需關心是否已經解碼

3. 檔案緩存

和未解碼的記憶體緩存相似,檔案緩存存儲的是未解碼的原始壓縮格式的圖檔,在使用之前同樣需要經過解碼等處理。

和記憶體緩存不一樣,APP在背景時,内容是不會被清空的。即使關機也不會。使用者可以随時用系統的設定菜單中進行清空緩存操作。

用一個檔案還是兩個檔案緩存?

如果要使用2個緩存,在配置image pipeline 時調用 ​

​setMainDiskCacheConfig​

​ 和 ​

​setSmallImageDiskCacheConfig​

​ 方法即可。

大部分的應用有一個檔案緩存就夠了,但是在一些情況下,你可能需要兩個緩存。比如你也許想把小檔案放在一個緩存中,大檔案放在另外一個檔案中,這樣小檔案就不會因大檔案的頻繁變動而被從緩存中移除。

至于什麼是小檔案,這個由應用來區分,在建立image request, 設定 ImageType 即可:

java
ImageRequest request = ImageRequest.newBuilderWithSourceUri(uri)
    .setImageType(ImageType.SMALL)      

如果你僅僅需要一個緩存,那麼不調用​

​setSmallImageDiskCacheConfig​

​即可。Image pipeline 預設會使用同一個緩存,同時​

​ImageType​

​也會被忽略。

記憶體用量的縮減

在 配置Image pipeline 時,我們可以指定每個緩存最大的記憶體用量。但是有時我們可能會想縮小記憶體用量。比如應用中有其他資料需要占用記憶體,不得不把圖檔緩存清除或者減小 或者我們想檢檢視看手機是否已經記憶體不夠了。

Fresco的緩存實作了DiskTrimmable 或者 MemoryTrimmable 接口。這兩個接口負責從各自的緩存中移除内容。

在應用中,可以給Image pipeline配置上實作了DiskTrimmableRegistry 和 MemoryTrimmableRegistry 接口的對象。

實作了這兩個接口的對象保持着一個清單,清單中的各個元素在記憶體不夠時,縮減各自的記憶體用量。