Android四大圖片快取框架之-Fresco(一)
本文來自於Fresco中文文件,這僅僅是自己的學習筆記!!!大牛繞路,放我我。
關於Fresco的介紹,請檢視連結
關於android圖片快取,這是一個android程式設計師必須瞭解的。關於四大圖片快取框架的特性與對比,請移步MDCC傳送門
首先說明,本文的大多數內容來自於官方文件,請勿噴!!!
那麼今天我們就來了解下Fresco,作為FB出版的開源專案,據說是目前最好的快取框架。
那麼我們就先來了解下Fresco是個什麼。
- Fresco是一個強大的圖片載入元件
- Fresco中設計有一個叫做image pipeline 的模組。他負責從網路,從本地檔案系統,本地資源載入圖片。為了最大限度上節省空間和CPU時間,它含有3級快取的設計(額,沒三級能拿出手?)
- Fresco中設計有一個叫做Drawees模組,方便地顯示loading圖,當圖片不再顯示在螢幕上時,及時地釋放記憶體和空間佔用。
- Fresco支援Android2.3及以上系統
簡單的看下使用SimpleDraweeView顯示一張佔位圖。在XML檔案中加入
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true"
>
</com.facebook.drawee.view.SimpleDraweeView>
在程式碼中設定Uri,
draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);
Uri uri = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/fresco-logo.png");
// draweeView.setController(draweeController);
draweeView.setImageURI(uri);
最後新增網路許可權,就可以了。我們在來看下這裡的Uri支援什麼格式:
- 遠端圖片 http:// 或者 https://
- 本地檔案 file://
- Content Provider content://
- asset目錄下的資源 asset://
- res目錄下的資源 res://包名/+R……
接下來便詳細的介紹Drawee
舉個栗子:
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="20dp"
android:layout_height="20dp"
fresco:fadeDuration="300"
fresco:actualImageScaleType="focusCrop"
fresco:placeholderImage="@color/wait_color"
fresco:placeholderImageScaleType="fitCenter"
fresco:failureImage="@drawable/error"
fresco:failureImageScaleType="centerInside"
fresco:retryImage="@drawable/retrying"
fresco:retryImageScaleType="centerCrop"
fresco:progressBarImage="@drawable/progress_bar"
fresco:progressBarImageScaleType="centerInside"
fresco:progressBarAutoRotateInterval="1000"
fresco:backgroundImage="@color/blue"
fresco:overlayImage="@drawable/watermark"
fresco:pressedStateOverlayImage="@color/red"
fresco:roundAsCircle="false"
fresco:roundedCornerRadius="1dp"
fresco:roundTopLeft="true"
fresco:roundTopRight="false"
fresco:roundBottomLeft="false"
fresco:roundBottomRight="true"
fresco:roundWithOverlayColor="@color/corner_color"
fresco:roundingBorderWidth="2dp"
fresco:roundingBorderColor="@color/border_color"
/>
上面這個是官方的栗子,上面有所有的屬性,我們就來看看,這些屬性代表什麼意思,
- layout_width和layout_height 不支援warp_content,但是可以通過setAspectRetio();來設定寬高比
- fadeDuration() 淡..時間
- actualImageScaleType 設定圖片縮放,通常使用foucsCrop,該屬性值會通過演算法把人頭像放在中間,關於縮放,請移步黑洞
- placeholderImage 下載成功之前顯示的圖片
- placeholderImageScaleType
- failureImage 載入失敗時顯示的圖片
- failureImageScaleType
- retryImage 載入失敗,提示使用者點選重新載入的圖片
- retryImageScaleType
- progressBarImage 提示 使用者正在載入,和進度無關
- progressBarImageScaleType
- progressBarAutoRotateInterval 圖片自動旋轉的時間間隔
- backgroundImage 背景
- overlayImage 疊加圖
- pressedStateOverlayImage 按下時候的疊加圖
- roundAsCircle 是否涉及圓圈
- roundedCornerRadius 圓角
- roundTopLeft、roundTopRight….. 分別設定4個角不同半徑,設定為true以後可以再程式碼中設定角度。通過RoundingParams的setConnersRadii()方法
public RoundingParams setCornersRadii(float topLeft, float topRight, float bottomRight, float bottomLeft) {
float[] radii = this.getOrCreateRoundedCornersRadii();
radii[0] = radii[1] = topLeft;
radii[2] = radii[3] = topRight;
radii[4] = radii[5] = bottomRight;
radii[6] = radii[7] = bottomLeft;
return this;
}
- roundWithOverlayColor,邊框的疊加顏色
- roundingBorderWidth 邊框寬度
roundingBorderColor 邊框顏色
我們看到,僅僅靠xml檔案的屬性,功能就已經很強大了。我們通過什麼來在程式碼中設定各種效果呢?看程式碼
GenericDraweeHierarchyBuilder builder =
new GenericDraweeHierarchyBuilder(getResources());
GenericDraweeHierarchy hierarchy = builder
.setFadeDuration(300)
.setPlaceholderImage(new MyCustomDrawable())
.setBackgrounds(backgroundList)
.setOverlays(overlaysList)
.build();
mSimpleDraweeView.setHierarchy(hierarchy);
DraweeHierarchy的一些屬性可以在執行時改變。
GenericDraweeHierarchy hierarchy =mSimpleDraweeView.getHierarchy();
hierarchy.setPlaceholderImage(R.drawable.placeholderId);
注意:對於同一個View,不要多次呼叫setHierarchy。
我們看看GenericDraweeHierarchy提供了哪些set方法
看到這裡有相當多的drawable啊。我們在來看看,Fresco原始碼中有哪些Drawable,
我們在set…(new ..Drawable),就可以輕鬆使用了。我們以ProgressBarDrawable為例,看看他提供了哪些方法。
,看起來還是很強大的。當然,我們可以自定義Drawable,關於自定義Drawable,我這裡就不再說了,網上還是很多的。
我們在來看看ControllerBuilder,從字面上就可以看出,這個可以對圖片做出一些控制。
ControllerListener listener = new BaseControllerListener() {...}
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(uri)
.setTapToRetryEnabled(true)
.setOldController(mSimpleDraweeView.getController())
.setControllerListener(listener)
.build();
mSimpleDraweeView.setController(controller);
在指定一個新的controller的時候,使用setOldController,可以節省不必要的記憶體分配。
我們來看看Fresco.newDraweeControllerBuilder()有哪些set方法。
自定義圖片載入請求
Uri uri;
Postprocessor myPostprocessor = new Postprocessor() { ... }
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setPostprocessor(myPostprocessor)
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setOldController(mSimpleDraweeView.getController())
// 其他設定
.build();
漸進式JPEG圖
ProgressiveJpegConfig pjpegConfig = new ProgressiveJpegConfig() {
@Override
public int getNextScanNumberToDecode(int scanNumber) {
return scanNumber + 2;
}
public QualityInfo getQualityInfo(int scanNumber) {
boolean isGoodEnough = (scanNumber >= 5);
return ImmutableQualityInfo.of(scanNumber, isGoodEnough, false);
}
}
ImagePipelineConfig config = ImagePipelineConfig.newBuilder()
.setProgressiveJpegConfig(pjpeg)
.build();
Uri uri;
ImageRequest request = ImageRequestBuilder
.newBuilderWithSource(uri)
.setProgressiveRenderingEnabled(true)
.build();
PipelineDraweeController controller = Fresco.newControllerBuilder()
.setImageRequest(requests)
.setOldController(mSimpleDraweeView.getController())
.build();
mSimpleDraweeView.setController(controller);
Gif動態圖
Uri uri;
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
. // other setters
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setAutoPlayAnimations(true)
. // other setters
.build();
mSimpleDraweeView.setController(controller);
手動控制動態圖播放
ControllerListener controllerListener = new BaseControllerListener<ImageInfo>() {
@Override
public void onFinalImageSet(
String id,
@Nullable ImageInfo imageInfo,
@Nullable Animatable anim) {
if (anim != null) {
// app-specific logic to enable animation starting
anim.start();
}
};
Uri uri;
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(uri)
.setControllerListener(controllerListener)
// other setters
.build();
mSimpleDraweeView.setController(controller);
使用動畫
Animatable animation = mSimpleDraweeView.getController().getAnimatable();
if (animation != null) {
// 開始播放
animation.start();
// 一段時間之後,根據業務邏輯,停止播放
animation.stop();
}
多圖請求以及圖片複用
Uri lowResUri, highResUri;
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setLowResImageRequest(ImageRequest.fromUri(lowResUri))
.setImageRequest(ImageRequest.fromUri(highResUri))
.setOldController(mSimpleDraweeView.getController())
.build();
mSimpleDraweeView.setController(controller);
縮圖預覽
Uri uri;
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setLocalThumbnailPreviewsEnabled(true)
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setOldController(mSimpleDraweeView.getController())
.build();
mSimpleDraweeView.setController(controller);
本地圖片複用
Uri uri1, uri2;
ImageRequest request = ImageRequest.fromUri(uri1);
ImageRequest request2 = ImageRequest.fromUri(uri2);
ImageRequest[] requests = { request1, request2 };
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setFirstAvailableImageRequests(requests)
.setOldController(mSimpleDraweeView.getController())
.build();
mSimpleDraweeView.setController(controller);
監聽下載事件
ControllerListener controllerListener = new BaseControllerListener<ImageInfo>() {
@Override
public void onFinalImageSet(
String id,
@Nullable ImageInfo imageInfo,
@Nullable Animatable anim) {
if (imageInfo == null) {
return;
}
QualityInfo qualityInfo = imageInfo.getQualityInfo();
FLog.d("Final image received! " +
"Size %d x %d",
"Quality level %d, good enough: %s, full quality: %s",
imageInfo.getWidth(),
imageInfo.getHeight(),
qualityInfo.getQuality(),
qualityInfo.isOfGoodEnoughQuality(),
qualityInfo.isOfFullQuality());
}
@Override
public void onIntermediateImageSet(String id, @Nullable ImageInfo imageInfo) {
FLog.d("Intermediate image received");
}
@Override
public void onFailure(String id, Throwable throwable) {
FLog.e(getClass(), throwable, "Error loading %s", id)
}
};
Uri uri;
DraweeController controller = Fresco.newControllerBuilder()
.setControllerListener(controllerListener)
.setUri(uri);
// other setters
.build();
mSimpleDraweeView.setController(controller);
修改圖片尺寸
Uri uri = "file:///mnt/sdcard/MyApp/myfile.jpg";
int width = 50, height = 50;
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setResizeOptions(new ResizeOptions(width, height))
.build();
PipelineDraweeController controller = Fresco.newDraweeControllerBuilder()
.setOldController(mDraweeView.getController())
.setImageRequest(request)
.build();
mSimpleDraweeView.setController(controller);
自動旋轉
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setAutoRotateEnabled(true)
.build();
圖片的修改。後處理器
Uri uri;
Postprocessor redMeshPostprocessor = new BasePostprocessor() {
@Override
public String getName() {
return "redMeshPostprocessor";
}
@Override
public void process(Bitmap bitmap) {
for (int x = 0; x < bitmap.getWidth(); x+=2) {
for (int y = 0; y < bitmap.getHeight(); y+=2) {
bitmap.setPixel(x, y, Color.RED);
}
}
}
}
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setPostprocessor(redMeshPostprocessor)
.build();
PipelineDraweeController controller = (PipelineDraweeController)
Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setOldController(mSimpleDraweeView.getController())
// other setters as you need
.build();
mSimpleDraweeView.setController(controller);
圖片請求 Image Requests
Uri uri;
ImageDecodeOptions decodeOptions = ImageDecodeOptions.newBuilder()
.setBackgroundColor(Color.GREEN)
.build();
ImageRequest request = ImageRequestBuilder
.newBuilderWithSource(uri)
.setAutoRotateEnabled(true)
.setLocalThumbnailPreviewsEnabled(true)
.setLowestPermittedRequestLevel(RequestLevel.FULL_FETCH)
.setProgressiveRenderingEnabled(false)
.setResizeOptions(new ResizeOptions(width, height))
.build();
上面我們說了Deawee,下面我們說下Image Pipeline
配置程式碼
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);
是在是太多了,我也懶的寫了。
參考資料:中文文件