Android圖片加載框架Fresco使用詳解

官方文檔: www.fresco-cn.org/docs/gettin…html

前言

Fresco是一個出自Facebook的功能強大的圖片加載庫java

優缺點

優勢:

1)內存自動回收。圖片不可見時,會及時自動釋放所佔用的內存,儘量地避免OOM 2)三級緩存機制。兩級內存緩存(解碼的與未解碼的)+一級磁盤緩存,提高加載速度,節省內存佔用空間 3)支持各類加載場景。如動圖加載、高斯模糊等常見的圖片加載場景。另外還提供了獨特的漸進式加載、先加載小圖再加載大圖,加載進度等功能(很強大)。android

缺點:

1)體積大(很胖)。較其餘主流圖片庫體積要大很多 2)侵入性較強。須使用它提供的SimpleDraweeView來代替ImageView加載顯示圖片 綜合來講,若是你的應用對圖片的顯示、加載等要求高的話,那就建議使用Fresco。但若是要求沒那麼高的話就用Glide或其它庫吧。git

介紹

下面經過 配置、SimpleDraweeView、加載圖片、混淆、其餘 這幾個部分來介紹。github

1. 配置

1.1 添加依賴web

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'//網絡實現層使用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 設置內存緩存bash

設置已解碼的內存緩存(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;//取手機內存最大值的五分之一做爲可用的最大內存數
MemoryCacheParams bitmapCacheParams = new MemoryCacheParams( //
// 可用最大內存數,以字節爲單位
MAX_MEMORY_CACHE_SIZE,
// 內存中容許的最多圖片數量
Integer.MAX_VALUE,
// 內存中準備清理可是還沒有刪除的總圖片所可用的最大內存數,以字節爲單位
MAX_MEMORY_CACHE_SIZE,
// 內存中準備清除的圖片最大數量
Integer.MAX_VALUE,
// 內存中單圖片的最大大小
Integer.MAX_VALUE);
return bitmapCacheParams;
}
});
複製代碼

設置未解碼的內存緩存框架

ImagePipelineConfig.Builder imagePipelineConfigBuilder = ImagePipelineConfig.newBuilder(context);
imagePipelineConfigBuilder.setEncodedMemoryCacheParamsSupplier(new Supplier<MemoryCacheParams>() {
public MemoryCacheParams get() {
MemoryCacheParams bitmapCacheParams;
//設置大小,可參考上面已解碼的內存緩存
return bitmapCacheParams;
}
});
複製代碼

1.4 設置內存緊張時的應對措施

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) {
//清空內存緩存
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) {
//返回下一個須要解碼的掃描次數
return scanNumber + 2;
}
public QualityInfo getQualityInfo(int scanNumber) {
boolean isGoodEnough = (scanNumber >= 5);
//肯定多少個掃描次數以後的圖片才能開始顯示。
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 容許解碼時調整圖片大小

容許後,便可在後面介紹的ImageRequest中對結合ResizeOptions對解碼後的圖片大小進行調整,從而優化了圖片所佔大小。默認只支持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="schemas.android.com/apk/res-aut…"

<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 旋轉進度條旋轉1圈所須要的時間

progressBarImage 旋轉進度條所使用的圖片

progressBarImageScaleType 旋轉進度條所使用的圖片的縮放樣式

retryImage 重試所使用的圖片

retryImageScaleType 重試所使用的圖片的縮放樣式

backgroundImage 背景圖片

overlayImage 覆蓋在加載完成後圖片上的疊加圖片

pressedStateOverlayImage 按壓狀態下的疊加圖片

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. 構建ImageRequest(加載路徑、開啓漸進式加載、圖片變換、調整解碼圖片大小等,可在這進行設置) 3. 構建DraweeController(動圖加載、失敗後點擊從新加載等,可在這進行設置) 4. 進行圖片加載

3.1 設置Hierarchay

雖然xml中的屬性都能在這一步經過代碼進行設置,但通常只在這設置一些統一固定的屬性,好比加載佔位圖、加載失敗圖等。 另外,顯示圖片的加載進度也是在這裏設置。

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進行設置,如各類狀態下顯示的圖片
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 構建ImageRequest

/**
* 構建、獲取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();
}
//根據請求路徑生成ImageRequest的構造者
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
//調整解碼圖片的大小
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 構建DraweeController

/**
* 構建、獲取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 進行圖片加載

建立一個loadImage方法將上面的Hierarchy、ImageRequest、DraweeController串在一塊兒,供具體的加載場景使用

/**
* 加載圖片核心方法
*
* @param simpleDraweeView 圖片加載控件
* @param uri 圖片加載地址
*/
public void loadImage(SimpleDraweeView simpleDraweeView, Uri uri) {
//設置Hierarchy
setHierarchay(simpleDraweeView.getHierarchy());
//構建並獲取ImageRequest
ImageRequest imageRequest = getImageRequest(uri, simpleDraweeView);
//構建並獲取Controller
DraweeController draweeController = getController(imageRequest, simpleDraweeView.getController());
//開始加載
simpleDraweeView.setController(draweeController);
}
複製代碼

具體的加載場景:

  • 加載網絡圖片,包括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);
}
複製代碼

加載網絡圖片,先加載小圖,待大圖加載完成後再替換掉小圖

這個須要修改一下DraweeController的構建,經過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());
//構建小圖的圖片請求
ImageRequest smallRequest = getImageRequest(smallUri, simpleDraweeView);
//構建大圖的圖片請求
ImageRequest bigRequest = getImageRequest(bigUri, simpleDraweeView);
//構建Controller
DraweeController draweeController = getSmallToBigController(smallRequest, bigRequest, simpleDraweeView.getController());
//開始加載
simpleDraweeView.setController(draweeController);
}
//加載網絡圖片,先加載小圖,待大圖加載完成後替換
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文件中添加如下內容進行混淆配置

-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採用三級緩存機制,兩級內存緩存+一級磁盤緩存,其中兩級內存緩存分爲已解碼的圖片緩存(Bitmap緩存)和未解碼的圖片緩存。 下面經過加載流程來了解其緩存策略。 1. 根據Uri到已解碼的圖片緩存中查找是否存在對應的Bitmap。若是存在,則返回Bitmap顯示; 若是不存在,則到未解碼的圖片緩存中查找。 2. 若是在未解碼的圖片緩存中存在對應的數據,則解碼,返回Bitmap顯示並將其加入到已解碼的圖片緩存中;若是不存在,則到磁盤緩存中查找。 3. 若是在磁盤緩存中存在對應的數據,則將數據加入到未解碼的圖片緩存中,而後解碼,返回Bitmap顯示並將其加入到已解碼的圖片緩存中;若是不存在,則進行網絡請求或者到本地文件加載。 4. 請求或加載成功後,將數據加入到磁盤緩存和未解碼的圖片緩存中,而後解碼,返回Bitmap顯示並將其加入到已解碼的圖片緩存中。 簡單整了個示意圖,幫助理解下:

緩存策略示意圖.png

5.2 兼容共享動畫 android5.0以後加入了共享動畫, 若是直接結合Fresco和共享動畫來實現頁面的過渡效果,會發現無效或異常。 Fresco官方也給出了說明,www.fresco-cn.org/docs/shared… 1.重寫共享動畫轉換效果的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 瀏覽大圖 「點擊小圖瀏覽大圖,而且大圖支持縮放。」 這種需求常常能見到,上面提到的SimpleDraweeView並不支持縮放等功能,因此須要從新定製一個控件來顯示。 官方給出了一個ZoomableDraweeView來支持該場景,另外也能夠參考PhotoDraweeView

5.4 獲取網絡請求回來的Bitmap 有時候,咱們須要拿到網絡請求回來的Bitmap對象,那麼咱們能夠這麼作:

//加載圖片,在ImageListener回調裏獲取返回的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());
    }
複製代碼

或者若是緩存裏有數據,能夠從緩存中取出而後轉爲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回調裏獲得下載結果

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();
// 獲取未解碼的圖片數據
        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());
    }
複製代碼
相關文章
相關標籤/搜索