官方文檔: https://www.fresco-cn.org/docs/getting-started.html
前言
Fresco是一個出自Facebook的功能強大的圖片加載庫
優(yōu)缺點
優(yōu)點:
1)內(nèi)存自動回收。圖片不可見時,會及時自動釋放所占用的內(nèi)存,盡可能地避免OOM
2)三級緩存機制。兩級內(nèi)存緩存(解碼的與未解碼的)+一級磁盤緩存,提升加載速度,節(jié)省內(nèi)存占用空間
3)支持各種加載場景。如動圖加載、高斯模糊等常見的圖片加載場景。另外還提供了獨特的漸進式加載、先加載小圖再加載大圖,加載進度等功能(很強大)。
缺點:
1)體積大(很胖)。較其他主流圖片庫體積要大不少
2)侵入性較強。須使用它提供的SimpleDraweeView來代替ImageView加載顯示圖片
綜合來說,如果你的應用對圖片的顯示、加載等要求高的話,那就建議使用Fresco。但如果要求沒那么高的話就用Glide或其它庫吧。
介紹
下面通過 配置、SimpleDraweeView、加載圖片、混淆、其他 這幾個部分來介紹。
1. 配置
1.1 添加依賴
compile 'com.facebook.fresco:fresco:1.5.0'
compile 'com.facebook.fresco:animated-gif:1.5.0'//加載gif動圖需添加此庫
compile 'com.facebook.fresco:animated-webp:1.5.0'//加載webp動圖需添加此庫
compile 'com.facebook.fresco:webpsupport:1.5.0'//支持webp需添加此庫
compile 'com.facebook.fresco:imagepipeline-okhttp3:1.5.0'//網(wǎng)絡實現(xiàn)層使用okhttp3需添加此庫
compile 'jp.wasabeef:fresco-processors:2.1.0@aar'//用于提供fresco的各種圖片變換
1.2 設置磁盤緩存
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setMainDiskCacheConfig(DiskCacheConfig.newBuilder(context)
.setBaseDirectoryPath(context.getExternalCacheDir())//設置磁盤緩存的路徑
.setBaseDirectoryName(BaseConstants.APP_IMAGE)//設置磁盤緩存文件夾的名稱
.setMaxCacheSize(MAX_DISK_CACHE_SIZE)//設置磁盤緩存的大小
.build());
1.3 設置內(nèi)存緩存
設置已解碼的內(nèi)存緩存(Bitmap緩存)
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setBitmapMemoryCacheParamsSupplier(new Supplier<MemoryCacheParams>() {
public MemoryCacheParams get() {
int MAX_HEAP_SIZE = (int) Runtime.getRuntime().maxMemory();
int MAX_MEMORY_CACHE_SIZE = MAX_HEAP_SIZE / 5;//取手機內(nèi)存最大值的五分之一作為可用的最大內(nèi)存數(shù)
MemoryCacheParams bitmapCacheParams = new MemoryCacheParams( //
// 可用最大內(nèi)存數(shù),以字節(jié)為單位
MAX_MEMORY_CACHE_SIZE,
// 內(nèi)存中允許的最多圖片數(shù)量
Integer.MAX_VALUE,
// 內(nèi)存中準備清理但是尚未刪除的總圖片所可用的最大內(nèi)存數(shù),以字節(jié)為單位
MAX_MEMORY_CACHE_SIZE,
// 內(nèi)存中準備清除的圖片最大數(shù)量
Integer.MAX_VALUE,
// 內(nèi)存中單圖片的最大大小
Integer.MAX_VALUE);
return bitmapCacheParams;
}
});
設置未解碼的內(nèi)存緩存
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setEncodedMemoryCacheParamsSupplier(new Supplier<MemoryCacheParams>() {
public MemoryCacheParams get() {
MemoryCacheParams bitmapCacheParams;
//設置大小,可參考上面已解碼的內(nèi)存緩存
return bitmapCacheParams;
}
});
1.4 設置內(nèi)存緊張時的應對措施
MemoryTrimmableRegistry memoryTrimmableRegistry = NoOpMemoryTrimmableRegistry.getInstance();
memoryTrimmableRegistry.registerMemoryTrimmable(new MemoryTrimmable() {
@Override
public void trim(MemoryTrimType trimType) {
final double suggestedTrimRatio = trimType.getSuggestedTrimRatio();
if (MemoryTrimType.OnCloseToDalvikHeapLimit.getSuggestedTrimRatio() == suggestedTrimRatio
|| MemoryTrimType.OnSystemLowMemoryWhileAppInBackground.getSuggestedTrimRatio() == suggestedTrimRatio
|| MemoryTrimType.OnSystemLowMemoryWhileAppInForeground.getSuggestedTrimRatio() == suggestedTrimRatio) {
//清空內(nèi)存緩存
ImagePipelineFactory.getInstance().getImagePipeline().clearMemoryCaches();
}
}
});
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setMemoryTrimmableRegistry(memoryTrimmableRegistry);
1.5 設置漸進式顯示的效果
ProgressiveJpegConfig progressiveJpegConfig = new ProgressiveJpegConfig() {
@Override
public int getNextScanNumberToDecode(int scanNumber) {
//返回下一個需要解碼的掃描次數(shù)
return scanNumber + 2;
}
public QualityInfo getQualityInfo(int scanNumber) {
boolean isGoodEnough = (scanNumber >= 5);
//確定多少個掃描次數(shù)之后的圖片才能開始顯示。
return ImmutableQualityInfo.of(scanNumber, isGoodEnough, false);
}
};
//具體含義可參考 http://wiki.jikexueyuan.com/project/fresco/progressive-jpegs.html
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setProgressiveJpegConfig(progressiveJpegConfig);
//或者使用默認的效果
//imagePipelineConfigBuilder.setProgressiveJpegConfig(new SimpleProgressiveJpegConfig());
設置完效果后,還需在下面介紹的ImageRequest中開啟漸進式加載。
1.6 允許解碼時調(diào)整圖片大小
允許后,即可在后面介紹的ImageRequest中對結(jié)合ResizeOptions對解碼后的圖片大小進行調(diào)整,從而優(yōu)化了圖片所占大小。默認只支持JPEG圖,所以要設置該屬性來支持png、jpg、webp。
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setDownsampleEnabled(true);
1.7 開啟Log
FLog.setMinimumLoggingLevel(FLog.VERBOSE);
Set<RequestListener> requestListeners = new HashSet<>();
requestListeners.add(new RequestLoggingListener());
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setRequestListeners(requestListeners);
1.8 初始化
上面的各種配置都是通過ImagePipelineConfig進行的,接著需要進行初始化,在Application中初始化即可
ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
//...進行各種設置
ImagePipelineConfig config = imagePipelineConfigBuilder.build();
Fresco.initialize(context, config);
如果想直接使用默認的配置,可以
Fresco.initialize(context);
2. SimpleDraweeView
Fresco要求使用SimpleDraweeView來替換ImageView進行圖片的加載與顯示,不少人也是因為這一點而不想使用Fresco。
下面介紹SimpleDraweeView在xml中的各種屬性
//在最外層布局的屬性中加入xmlns:fresco="http://schemas.android.com/apk/res-auto"
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv"
android:layout_width="150dp"
android:layout_height="150dp"
fresco:actualImageScaleType="centerCrop"
fresco:fadeDuration="2000"
fresco:failureImage="@mipmap/ic_launcher"
fresco:failureImageScaleType="centerCrop"
fresco:placeholderImage="@mipmap/ic_launcher"
fresco:placeholderImageScaleType="centerCrop"
fresco:progressBarImage="@drawable/rotate"
fresco:progressBarImageScaleType="centerCrop"
fresco:retryImage="@mipmap/ic_launcher"
fresco:retryImageScaleType="centerCrop"
fresco:backgroundImage="@mipmap/ic_launcher"
fresco:overlayImage="@mipmap/ic_launcher"
fresco:pressedStateOverlayImage="@mipmap/ic_launcher"
fresco:roundAsCircle="false"
fresco:roundedCornerRadius="7dp"
fresco:roundTopLeft="true"
fresco:roundTopRight="false"
fresco:roundBottomLeft="false"
fresco:roundBottomRight="true"
fresco:roundWithOverlayColor="@color/colorAccent"
fresco:roundingBorderWidth="2dp"
fresco:roundingBorderColor="@color/colorPrimary"
fresco:viewAspectRatio="1"/>
屬性 作用說明
actualImageScaleType 加載完成的圖片的縮放樣式
fadeDuration 由進度條和占位符圖片漸變過渡到加載完成的圖片所使用的時間間隔
failureImage 加載失敗所使用的圖片
failureImageScaleType 加載失敗所使用的圖片的縮放樣式
placeholderImage 占位符圖片
placeholderImageScaleType 占位符圖片的縮放樣式
progressBarAutoRotateInterval 旋轉(zhuǎn)進度條旋轉(zhuǎn)1圈所需要的時間
progressBarImage 旋轉(zhuǎn)進度條所使用的圖片
progressBarImageScaleType 旋轉(zhuǎn)進度條所使用的圖片的縮放樣式
retryImage 重試所使用的圖片
retryImageScaleType 重試所使用的圖片的縮放樣式
backgroundImage 背景圖片
overlayImage 覆蓋在加載完成后圖片上的疊加圖片
pressedStateOverlayImage 按壓狀態(tài)下的疊加圖片
roundAsCircle 是否將圖片剪切為圓形
roundedCornerRadius 圓角圖片時候,圓角的半徑大小
roundTopLeft 左上角是否為圓角
roundTopRight 右上角是否為圓角
roundBottomLeft 左下角是否為圓角
roundBottomRight 右下角是否為圓角
roundWithOverlayColor 圓角或圓形圖疊加的顏色,只能是顏色
roundingBorderWidth 圓角或圓形圖邊框的寬度
roundingBorderColor 圓角或圓形圖邊框的顏色
viewAspectRatio 設置寬高比
*注意:
1)android:src屬性對于SimpleDraweeView無效,必要的話可用fresco:placeholderImage來設置。
2)SimpleDraweeView不支持android:layout_width和android:layout_height同時都設為wrap_content。
3. 加載圖片
使用Fresco加載圖片,大致是按以下流程進行的。
1. 設置Hierarchay(上面xml中的屬性以及顯示加載進度條等,可在這進行設置)
2. 構(gòu)建ImageRequest(加載路徑、開啟漸進式加載、圖片變換、調(diào)整解碼圖片大小等,可在這進行設置)
3. 構(gòu)建DraweeController(動圖加載、失敗后點擊重新加載等,可在這進行設置)
4. 進行圖片加載
3.1 設置Hierarchay
雖然xml中的屬性都能在這一步通過代碼進行設置,但一般只在這設置一些統(tǒng)一固定的屬性,比如加載占位圖、加載失敗圖等。 另外,顯示圖片的加載進度也是在這里設置。
Resources res = MyApplication.getInstance().getResources();
Drawable retryImage = ResourcesCompat.getDrawable(res, R.mipmap.ic_image_load, null);
Drawable failureImage = ResourcesCompat.getDrawable(res, R.mipmap.ic_image_load, null);
Drawable placeholderImage = ResourcesCompat.getDrawable(res, R.mipmap.ic_image_load, null);
//對Hierarchy進行設置,如各種狀態(tài)下顯示的圖片
public void setHierarchay(GenericDraweeHierarchy hierarchy) {
if (hierarchy != null) {
//重新加載顯示的圖片
hierarchy.setRetryImage(retryImage);
//加載失敗顯示的圖片
hierarchy.setFailureImage(failureImage, ScalingUtils.ScaleType.CENTER_CROP);
//加載完成前顯示的占位圖
hierarchy.setPlaceholderImage(placeholderImage, ScalingUtils.ScaleType.CENTER_CROP);
//設置加載成功后圖片的縮放模式
hierarchy.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP);
//顯示加載進度條,使用自帶的new ProgressBarDrawable()
//默認會顯示在圖片的底部,可以設置進度條的顏色。
hierarchy.setProgressBarImage(new ProgressBarDrawable());
//設置圖片加載為圓形
hierarchy.setRoundingParams(RoundingParams.asCircle());
//設置圖片加載為圓角,并可設置圓角大小
hierarchy.setRoundingParams(RoundingParams.fromCornersRadius(radius));
//其他設置請查看具體API。
}
}
3.2 構(gòu)建ImageRequest
/**
* 構(gòu)建、獲取ImageRequest
* @param uri 加載路徑
* @param simpleDraweeView 加載的圖片控件
* @return ImageRequest
*/
public ImageRequest getImageRequest(Uri uri, SimpleDraweeView simpleDraweeView) {
int width;
int height;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
width = simpleDraweeView.getWidth();
height = simpleDraweeView.getHeight();
} else {
width = simpleDraweeView.getMaxWidth();
height = simpleDraweeView.getMaxHeight();
}
//根據(jù)請求路徑生成ImageRequest的構(gòu)造者
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
//調(diào)整解碼圖片的大小
if (width > 0 && height > 0) {
builder.setResizeOptions(new ResizeOptions(width, height));
}
//設置是否開啟漸進式加載,僅支持JPEG圖片
builder.setProgressiveRenderingEnabled(true);
//圖片變換處理
CombinePostProcessors.Builder processorBuilder = new CombinePostProcessors.Builder();
//加入模糊變換
processorBuilder.add(new BlurPostprocessor(context, radius));
//加入灰白變換
processorBuilder.add(new GrayscalePostprocessor());
//應用加入的變換
builder.setPostprocessor(processorBuilder.build());
//更多圖片變換請查看https://github.com/wasabeef/fresco-processors
return builder.build();
}
3.3 構(gòu)建DraweeController
/**
* 構(gòu)建、獲取Controller
* @param request
* @param oldController
* @return
*/
public DraweeController getController(ImageRequest request, @Nullable DraweeController oldController) {
PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder();
builder.setImageRequest(request);//設置圖片請求
builder.setTapToRetryEnabled(false);//設置是否允許加載失敗時點擊再次加載
builder.setAutoPlayAnimations(true);//設置是否允許動畫圖自動播放
builder.setOldController(oldController);
return builder.build();
}
3.4 進行圖片加載
創(chuàng)建一個loadImage方法將上面的Hierarchy、ImageRequest、DraweeController串在一起,供具體的加載場景使用
/**
* 加載圖片核心方法
*
* @param simpleDraweeView 圖片加載控件
* @param uri 圖片加載地址
*/
public void loadImage(SimpleDraweeView simpleDraweeView, Uri uri) {
//設置Hierarchy
setHierarchay(simpleDraweeView.getHierarchy());
//構(gòu)建并獲取ImageRequest
ImageRequest imageRequest = getImageRequest(uri, simpleDraweeView);
//構(gòu)建并獲取Controller
DraweeController draweeController = getController(imageRequest, simpleDraweeView.getController());
//開始加載
simpleDraweeView.setController(draweeController);
}
具體的加載場景:
- 加載網(wǎng)絡圖片,包括gif/webp動圖
public void loadNetImage(SimpleDraweeView simpleDraweeView, String url) {
Uri uri = Uri.parse(url);
loadImage(simpleDraweeView, uri);
}
加載本地文件圖片
public void loadLocalImage(SimpleDraweeView simpleDraweeView, String fileName) {
Uri uri = Uri.parse("file://" + fileName);
loadImage(simpleDraweeView, uri);
}
加載res下資源圖片
public void loadResourceImage(SimpleDraweeView simpleDraweeView, @DrawableRes int resId) {
Uri uri = Uri.parse("res:///" + resId);
loadImage(simpleDraweeView, uri);
}
加載ContentProvider下的圖片
public void loadContentProviderImage(SimpleDraweeView simpleDraweeView, int resId) {
Uri uri = Uri.parse("content:///" + resId);
loadImage(simpleDraweeView, uri);
}
加載asset下的圖片
public void loadAssetImage(SimpleDraweeView simpleDraweeView, int resId) {
Uri uri = Uri.parse("asset:///" + resId);
}
加載網(wǎng)絡圖片,先加載小圖,待大圖加載完成后再替換掉小圖
這個需要修改一下DraweeController的構(gòu)建,通過setLowResImageRequest來添加小圖請求
public DraweeController getSmallToBigController(ImageRequest smallRequest, ImageRequest bigRequest, @Nullable DraweeController oldController) {
PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder();
builder.setLowResImageRequest(smallRequest);//小圖的圖片請求
builder.setImageRequest(bigRequest);//大圖的圖片請求
builder.setTapToRetryEnabled(false);//設置是否允許加載失敗時點擊再次加載
builder.setAutoPlayAnimations(true);//設置是否允許動畫圖自動播放
builder.setOldController(oldController);
return builder.build();
}
public void loadImageSmallToBig(SimpleDraweeView simpleDraweeView, Uri smallUri, Uri bigUri) {
//設置Hierarchy
setHierarchay(simpleDraweeView.getHierarchy());
//構(gòu)建小圖的圖片請求
ImageRequest smallRequest = getImageRequest(smallUri, simpleDraweeView);
//構(gòu)建大圖的圖片請求
ImageRequest bigRequest = getImageRequest(bigUri, simpleDraweeView);
//構(gòu)建Controller
DraweeController draweeController = getSmallToBigController(smallRequest, bigRequest, simpleDraweeView.getController());
//開始加載
simpleDraweeView.setController(draweeController);
}
//加載網(wǎng)絡圖片,先加載小圖,待大圖加載完成后替換
public void loadNetImageSmallToBig(SimpleDraweeView simpleDraweeView, String smallUrl, String bigUrl) {
Uri smallUri = Uri.parse(smallUrl);
Uri bigUri = Uri.parse(bigUrl);
loadImageSmallToBig(simpleDraweeView, smallUri, bigUri);
}
4. 混淆
在proguard-rules.pro文件中添加以下內(nèi)容進行混淆配置
-keep class com.facebook.fresco.** { *; }
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
-keep @com.facebook.common.internal.DoNotStrip class *
-keepclassmembers class * {
@com.facebook.common.internal.DoNotStrip *;
}
-keep class com.facebook.imagepipeline.gif.** { *; }
-keep class com.facebook.imagepipeline.webp.* { *; }
-keepclassmembers class * {
native <methods>;
}
-dontwarn okio.**
-dontwarn com.squareup.okhttp.**
-dontwarn okhttp3.**
-dontwarn javax.annotation.**
-dontwarn com.android.volley.toolbox.**
-keep class com.facebook.imagepipeline.animated.factory.AnimatedFactoryImpl {
public AnimatedFactoryImpl(com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory,com.facebook.imagepipeline.core.ExecutorSupplier);
}
5. 其他
5.1 緩存策略
Fresco采用三級緩存機制,兩級內(nèi)存緩存+一級磁盤緩存,其中兩級內(nèi)存緩存分為已解碼的圖片緩存(Bitmap緩存)和未解碼的圖片緩存。
下面通過加載流程來了解其緩存策略。
1. 根據(jù)Uri到已解碼的圖片緩存中查找是否存在對應的Bitmap。如果存在,則返回Bitmap顯示;
如果不存在,則到未解碼的圖片緩存中查找。
2. 如果在未解碼的圖片緩存中存在對應的數(shù)據(jù),則解碼,返回Bitmap顯示并將其加入到已解碼的圖片緩存中;如果不存在,則到磁盤緩存中查找。
3. 如果在磁盤緩存中存在對應的數(shù)據(jù),則將數(shù)據(jù)加入到未解碼的圖片緩存中,然后解碼,返回Bitmap顯示并將其加入到已解碼的圖片緩存中;如果不存在,則進行網(wǎng)絡請求或者到本地文件加載。
4. 請求或加載成功后,將數(shù)據(jù)加入到磁盤緩存和未解碼的圖片緩存中,然后解碼,返回Bitmap顯示并將其加入到已解碼的圖片緩存中。
簡單整了個示意圖,幫助理解下:

5.2 兼容共享動畫
android5.0之后加入了共享動畫,
如果直接結(jié)合Fresco和共享動畫來實現(xiàn)頁面的過渡效果,會發(fā)現(xiàn)無效或異常。
Fresco官方也給出了說明,https://www.fresco-cn.org/docs/shared-transitions.html
1.重寫共享動畫轉(zhuǎn)換效果的xml文件,注釋掉changeImageTransform,并將該文件放于res/transition文件夾下
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<explode/>
<changeBounds/>
<changeTransform/>
<changeClipBounds/>
<!--<changeImageTransform/>-->
<!-- Fresco圖片框架不支持changeImageTransform變換,
默認情況是這五個變換都使用,所以需要重寫xml并注釋掉changeImageTransform -->
</transitionSet>
2.在style文件中使用上一步重寫的xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="AppTheme.Base">
<!-- 允許使用transitions -->
<item name="android:windowContentTransitions">true</item>
<!-- 指定shared element transitions -->
<item name="android:windowSharedElementEnterTransition">
@transition/share_element_transition</item>
<item name="android:windowSharedElementExitTransition">
@transition/share_element_transition</item>
</style>
</resources>
5.3 瀏覽大圖
“點擊小圖瀏覽大圖,并且大圖支持縮放?!?br>
這種需求經(jīng)常能見到,上面提到的SimpleDraweeView并不支持縮放等功能,所以需要重新定制一個控件來顯示。
官方給出了一個ZoomableDraweeView來支持該場景,另外也可以參考PhotoDraweeView
5.4 獲取網(wǎng)絡請求回來的Bitmap
有時候,我們需要拿到網(wǎng)絡請求回來的Bitmap對象,那么我們可以這么做:
//加載圖片,在ImageListener回調(diào)里獲取返回的Bitmap
public void getBitmap(Context context, String url, final ImageListener<Bitmap> imageListener) {
Uri uri = Uri.parse(url);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
ImageRequest imageRequest = builder.build();
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, context);
dataSource.subscribe(new BaseDataSubscriber<CloseableReference<CloseableImage>>() {
@Override
public void onNewResultImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
if (!dataSource.isFinished()) {
return;
}
CloseableReference<CloseableImage> imageReference = dataSource.getResult();
if (imageReference != null) {
final CloseableReference<CloseableImage> closeableReference = imageReference.clone();
try {
CloseableImage closeableImage = closeableReference.get();
//動圖處理
if (closeableImage instanceof CloseableAnimatedImage) {
AnimatedImageResult animatedImageResult = ((CloseableAnimatedImage) closeableImage).getImageResult();
if (animatedImageResult != null && animatedImageResult.getImage() != null) {
int imageWidth = animatedImageResult.getImage().getWidth();
int imageHeight = animatedImageResult.getImage().getHeight();
Bitmap.Config bitmapConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = Bitmap.createBitmap(imageWidth, imageHeight, bitmapConfig);
animatedImageResult.getImage().getFrame(0).renderFrame(imageWidth, imageHeight, bitmap);
if (imageListener != null) {
imageListener.onSuccess(bitmap);
}
}
}
//非動圖處理
else if (closeableImage instanceof CloseableBitmap) {
CloseableBitmap closeableBitmap = (CloseableBitmap) closeableImage;
Bitmap bitmap = closeableBitmap.getUnderlyingBitmap();
if (bitmap != null && !bitmap.isRecycled()) {
final Bitmap tempBitmap = bitmap.copy(bitmap.getConfig(), false);
if (imageListener != null) {
imageListener.onSuccess(tempBitmap);
}
}
}
} finally {
imageReference.close();
closeableReference.close();
}
}
}
@Override
public void onFailureImpl(DataSource dataSource) {
Throwable throwable = dataSource.getFailureCause();
if (imageListener != null) {
imageListener.onFail(throwable);
}
}
}, UiThreadImmediateExecutorService.getInstance());
}
或者如果緩存里有數(shù)據(jù),可以從緩存中取出然后轉(zhuǎn)為bitmap
FileBinaryResource resource = (FileBinaryResource) Fresco.getImagePipelineFactory().getMainFileCache().getResource(new SimpleCacheKey(url));
if (resource != null && resource.getFile() != null) {
Bitmap bitmap = BitmapFactory.decodeFile(resource.getFile().getAbsolutePath());
}
5.5 下載圖片
下載圖片到指定位置,在ImageListener回調(diào)里得到下載結(jié)果
public void downLoadImage(Context context, String url, final File saveFile, final ImageListener<File> imageListener) {
Uri uri = Uri.parse(url);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
ImageRequest imageRequest = builder.build();
// 獲取未解碼的圖片數(shù)據(jù)
DataSource<CloseableReference<PooledByteBuffer>> dataSource = imagePipeline.fetchEncodedImage(imageRequest, context);
dataSource.subscribe(new BaseDataSubscriber<CloseableReference<PooledByteBuffer>>() {
@Override
public void onNewResultImpl(DataSource<CloseableReference<PooledByteBuffer>> dataSource) {
if (!dataSource.isFinished()) {
return;
}
CloseableReference<PooledByteBuffer> imageReference = dataSource.getResult();
if (imageReference != null) {
final CloseableReference<PooledByteBuffer> closeableReference = imageReference.clone();
try {
PooledByteBuffer pooledByteBuffer = closeableReference.get();
InputStream inputStream = new PooledByteBufferInputStream(pooledByteBuffer);
OutputStream outputStream = new FileOutputStream(saveFile);
if (FileUtil.saveFile(inputStream, outputStream) && imageListener != null) {
imageListener.onSuccess(saveFile);
}
} catch (Exception e) {
if (imageListener != null) {
imageListener.onFail(e);
}
e.printStackTrace();
} finally {
imageReference.close();
closeableReference.close();
}
}
}
@Override
public void onProgressUpdate(DataSource<CloseableReference<PooledByteBuffer>> dataSource) {
int progress = (int) (dataSource.getProgress() * 100);
RingLog.d("fresco下載圖片進度:" + progress);
}
@Override
public void onFailureImpl(DataSource dataSource) {
Throwable throwable = dataSource.getFailureCause();
if (imageListener != null) {
imageListener.onFail(throwable);
}
}
},
Executors.newSingleThreadExecutor());
}