Android圖片加載神器之Fresco,基于各種使用場(chǎng)景的講解

如果你已習(xí)慣了Glide、Picasso的使用方式, Fresco能不能像Glide、Picasso 一樣使用呢?可以看看這個(gè)開源庫(kù):https://github.com/hpdx/fresco-helper

Fresco是Facebook開源Android平臺(tái)上一個(gè)強(qiáng)大的圖片加載庫(kù),也是迄今為止Android平臺(tái)上最強(qiáng)大的圖片加載庫(kù)。

優(yōu)點(diǎn):相對(duì)于其他開源的第三方圖片加載庫(kù),F(xiàn)resco擁有更好的內(nèi)存管理和強(qiáng)大的功能,基本上能滿足所有的日常使用場(chǎng)景。

缺點(diǎn):整體比較大,不過(guò)目前的版本已做了拆分,你只需要導(dǎo)入你使用到的功能相關(guān)的庫(kù)。從代碼層面來(lái)說(shuō)侵入性太強(qiáng),體現(xiàn)在要使用它需要用Fresco的組件SimpleDraweeView替換掉Android原生圖片顯示組件ImageView,這也是很多人不愿意在項(xiàng)目中接入Fresco的主要原因。

特性:
1、內(nèi)存管理
解壓后的圖片,即Android中的Bitmap,占用大量的內(nèi)存。大的內(nèi)存占用勢(shì)必引發(fā)更加頻繁的GC。在5.0以下,GC將會(huì)顯著地引發(fā)界面卡頓。
在5.0以下系統(tǒng),F(xiàn)resco將圖片放到一個(gè)特別的內(nèi)存區(qū)域。當(dāng)然,在圖片不顯示的時(shí)候,占用的內(nèi)存會(huì)自動(dòng)被釋放。這會(huì)使得APP更加流暢,減少因圖片內(nèi)存占用而引發(fā)的OOM。

2、Image Pipeline
Fresco中設(shè)計(jì)有一個(gè)叫做 Image Pipeline 的模塊。它負(fù)責(zé)從網(wǎng)絡(luò),從本地文件系統(tǒng),本地資源加載圖片和管理。為了最大限度節(jié)省空間和CPU時(shí)間,它含有3級(jí)緩存設(shè)計(jì)(2級(jí)內(nèi)存,1級(jí)磁盤)。兩個(gè)內(nèi)存緩存為Bitmap緩存和未解碼的圖片緩存,這樣既可以加快圖片的加載速度,又能節(jié)省內(nèi)存的占用(解碼后的圖片就是Bitmap,其占用內(nèi)存相對(duì)未解碼的圖片數(shù)據(jù)而言會(huì)大很多)。
Image pipeline 負(fù)責(zé)完成加載圖像,變成Android設(shè)備可呈現(xiàn)的形式所要經(jīng)歷的大致流程如下:
a、根據(jù)Uri在已解碼的(Bitmap緩存)內(nèi)存緩存中查找,找到了則返回Bitmap對(duì)象;如果沒找到,則開啟后臺(tái)線程開始后續(xù)的工作。
b、根據(jù)Uri在未解碼的內(nèi)存緩存中查找,若找到了則解碼,然后緩存到已解碼的內(nèi)存緩存中,并且返回Bitmap對(duì)象。
d、如果在未解碼的內(nèi)存緩存中沒找到,則根據(jù)Uri在磁盤緩存中查找,若找到了則讀取數(shù)據(jù)(byte數(shù)組),并緩存到未解碼的內(nèi)存緩存中,解碼、然后緩存到已解碼的內(nèi)存緩存中,并且返回Bitmap對(duì)象。
e、如果在磁盤緩存中沒找到,則從網(wǎng)絡(luò)或者本地加載數(shù)據(jù)。加載完成后,依次緩存到磁盤緩存未解碼的內(nèi)存緩存中。解碼、然后緩存到已解碼的內(nèi)存緩存中,并且返回Bitmap對(duì)象。

其流程圖如下:


這里寫圖片描述

3、Drawees
Fresco 中設(shè)計(jì)有一個(gè)叫做 Drawees 模塊,負(fù)責(zé)圖片的呈現(xiàn)。它由三個(gè)元素組成分別是:
DraweeView 繼承于 View, 負(fù)責(zé)圖片的顯示。
DraweeHierarchy 用于組織和維護(hù)最終繪制和呈現(xiàn)的 Drawable 對(duì)象。
DraweeController 負(fù)責(zé)和ImagePipeline的交互,可以創(chuàng)建一個(gè)這個(gè)類的實(shí)例,來(lái)實(shí)現(xiàn)對(duì)所要顯示的圖片做更多的控制。
一般情況下,使用 SimpleDraweeView 即可,你可以配置其XML屬性來(lái)實(shí)現(xiàn)各式各樣的展示效果。
a、在圖片加載完成前顯示占位圖;
b、在圖片加載的過(guò)程中顯示加載進(jìn)度圖;
c、加載成功后,將占位圖或者加載進(jìn)度圖,自動(dòng)替換為目標(biāo)圖片。
d、加載失敗后,它會(huì)顯示加載失敗的圖(若沒配置加載失敗的圖,則顯示的是占位圖)
e、加載失敗后,若配置過(guò)重試圖,則會(huì)顯示重試圖,用戶點(diǎn)擊可以重新去加載圖片(默認(rèn)配置可重試3次)
f、自定義居中焦點(diǎn)(配合Google提供的服務(wù)可以實(shí)現(xiàn)人臉識(shí)別,經(jīng)測(cè)試國(guó)內(nèi)目前使用不了)
g、顯示圓角圖、圓形圖和圓圈;
h、添加覆蓋物(圖層疊加);
j、 實(shí)現(xiàn)圖片的按下效果;
k、圖片的漸進(jìn)式呈現(xiàn);(目前只支持Jpeg格式的圖片)
x、當(dāng)圖片不再顯示在屏幕上時(shí),它會(huì)及時(shí)地釋放內(nèi)存和空間占用。

4、Fresco目前所支持的圖片格式
a、靜態(tài)圖:png、jpg、web
b、動(dòng)態(tài)圖:gif、web格式的gif

以上聊了這么多,大概意思就是Fresco出身名門,很好很強(qiáng)大,超牛逼!接下來(lái)我們來(lái)聊聊在項(xiàng)目中的具體使用。我專門寫了一個(gè)針對(duì)Fresco的使用幫助庫(kù),先給大家看看Demo的運(yùn)行效果圖:


常見的各種效果


從網(wǎng)絡(luò)加載的圖片墻


點(diǎn)擊圖片墻中的照片后,打開的瀏覽大圖界面


一、Fresco的引入及ImagePipeline參數(shù)配置
1、在build.gradle文件中添加依賴

dependencies {
    // ......

    compile 'com.facebook.fresco:fresco:0.14.1'
    compile 'com.facebook.fresco:animated-base-support:0.14.1'
    compile 'com.facebook.fresco:animated-gif:0.14.1'
    compile 'com.facebook.fresco:webpsupport:0.14.1'
    compile 'com.facebook.fresco:animated-webp:0.14.1'
    compile 'com.facebook.fresco:imagepipeline-okhttp3:0.14.1'
}

a、在 API < 14 上的機(jī)器支持 WebP 時(shí),需要添加以下依賴

compile 'com.facebook.fresco:animated-base-support:0.14.1'

b、支持GIF動(dòng)圖,需要添加以下依賴

 compile 'com.facebook.fresco:animated-gif:0.14.1'

c、支持WebP,需要添加以下依賴

compile 'com.facebook.fresco:webpsupport:0.14.1'

d、支持WebP動(dòng)圖,需要添加以下依賴

 compile 'com.facebook.fresco:animated-webp:0.14.1'

e、網(wǎng)絡(luò)實(shí)現(xiàn)層想使用okhttp3,需要添加以下依賴

compile 'com.facebook.fresco:imagepipeline-okhttp3:0.14.1'

2、ImagePipeline配置
a、磁盤緩存目錄,推薦緩存到應(yīng)用本身的緩存文件夾,這么做的好處是:當(dāng)應(yīng)用被用戶卸載后能自動(dòng)清除緩存,增加用戶好感(可能以后用得著時(shí),還會(huì)想起我);一些內(nèi)存清理軟件可以掃描出來(lái),進(jìn)行內(nèi)存的清理。

File fileCacheDir = context.getApplicationContext().getCacheDir();

b、配置磁盤緩存,大部分的應(yīng)用有一個(gè)磁盤緩存就夠了,但是在一些情況下,你可能需要兩個(gè)緩存。比如你想把小文件放在一個(gè)緩存中(50*50及以下尺寸),大文件放在另外一個(gè)文件中,這樣小文件就不會(huì)因大文件的頻繁變動(dòng)而被從緩存中移除。

 DiskCacheConfig mainDiskCacheConfig = DiskCacheConfig.newBuilder(context)
                    .setBaseDirectoryName(IMAGE_PIPELINE_CACHE_DIR)
                    .setBaseDirectoryPath(fileCacheDir)
                    .build();

            DiskCacheConfig smallDiskCacheConfig = DiskCacheConfig.newBuilder(context)
                    .setBaseDirectoryPath(fileCacheDir)
                    .setBaseDirectoryName(IMAGE_PIPELINE_SMALL_CACHE_DIR)
                    .setMaxCacheSize(MAX_DISK_SMALL_CACHE_SIZE)
                    .setMaxCacheSizeOnLowDiskSpace(MAX_DISK_SMALL_ONLOWDISKSPACE_CACHE_SIZE)
                    .build();

c、ImagePipeline的完整配置代碼如下:

package com.facebook.fresco.helper.config;

import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;

import com.facebook.cache.disk.DiskCacheConfig;
import com.facebook.common.logging.FLog;
import com.facebook.common.memory.MemoryTrimType;
import com.facebook.common.memory.MemoryTrimmable;
import com.facebook.common.memory.MemoryTrimmableRegistry;
import com.facebook.common.memory.NoOpMemoryTrimmableRegistry;
import com.facebook.common.util.ByteConstants;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.fresco.helper.utils.MLog;
import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory;
import com.facebook.imagepipeline.core.ImagePipelineConfig;
import com.facebook.imagepipeline.decoder.ProgressiveJpegConfig;
import com.facebook.imagepipeline.image.ImmutableQualityInfo;
import com.facebook.imagepipeline.image.QualityInfo;
import com.facebook.imagepipeline.listener.RequestListener;
import com.facebook.imagepipeline.listener.RequestLoggingListener;

import java.io.File;
import java.util.HashSet;
import java.util.Set;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;

/**
 *
 * Created by android_ls on 16/9/8.
 */
public class ImageLoaderConfig {

    private static final String IMAGE_PIPELINE_CACHE_DIR = "image_cache";

    private static final String IMAGE_PIPELINE_SMALL_CACHE_DIR = "image_small_cache";

    private static final int MAX_DISK_SMALL_CACHE_SIZE = 10 * ByteConstants.MB;

    private static final int MAX_DISK_SMALL_ONLOWDISKSPACE_CACHE_SIZE = 5 * ByteConstants.MB;

    private static ImagePipelineConfig sImagePipelineConfig;

    /**
     * Creates config using android http stack as network backend.
     */
    public static ImagePipelineConfig getImagePipelineConfig(final Context context) {
        if (sImagePipelineConfig == null) {
            /**
             * 推薦緩存到應(yīng)用本身的緩存文件夾,這么做的好處是:
             * 1、當(dāng)應(yīng)用被用戶卸載后能自動(dòng)清除緩存,增加用戶好感(可能以后用得著時(shí),還會(huì)想起我)
             * 2、一些內(nèi)存清理軟件可以掃描出來(lái),進(jìn)行內(nèi)存的清理
             */
            File fileCacheDir = context.getApplicationContext().getCacheDir();
//            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//                fileCacheDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Fresco");
//            }

            DiskCacheConfig mainDiskCacheConfig = DiskCacheConfig.newBuilder(context)
                    .setBaseDirectoryName(IMAGE_PIPELINE_CACHE_DIR)
                    .setBaseDirectoryPath(fileCacheDir)
                    .build();

            DiskCacheConfig smallDiskCacheConfig = DiskCacheConfig.newBuilder(context)
                    .setBaseDirectoryPath(fileCacheDir)
                    .setBaseDirectoryName(IMAGE_PIPELINE_SMALL_CACHE_DIR)
                    .setMaxCacheSize(MAX_DISK_SMALL_CACHE_SIZE)
                    .setMaxCacheSizeOnLowDiskSpace(MAX_DISK_SMALL_ONLOWDISKSPACE_CACHE_SIZE)
                    .build();

            FLog.setMinimumLoggingLevel(FLog.VERBOSE);
            Set<RequestListener> requestListeners = new HashSet<>();
            requestListeners.add(new RequestLoggingListener());

            // 當(dāng)內(nèi)存緊張時(shí)采取的措施
            MemoryTrimmableRegistry memoryTrimmableRegistry = NoOpMemoryTrimmableRegistry.getInstance();
            memoryTrimmableRegistry.registerMemoryTrimmable(new MemoryTrimmable() {
                @Override
                public void trim(MemoryTrimType trimType) {
                    final double suggestedTrimRatio = trimType.getSuggestedTrimRatio();
                    MLog.i(String.format("Fresco onCreate suggestedTrimRatio : %d", suggestedTrimRatio));

                    if (MemoryTrimType.OnCloseToDalvikHeapLimit.getSuggestedTrimRatio() == suggestedTrimRatio
                            || MemoryTrimType.OnSystemLowMemoryWhileAppInBackground.getSuggestedTrimRatio() == suggestedTrimRatio
                            || MemoryTrimType.OnSystemLowMemoryWhileAppInForeground.getSuggestedTrimRatio() == suggestedTrimRatio
                            ) {
                        // 清除內(nèi)存緩存
                        Fresco.getImagePipeline().clearMemoryCaches();
                    }
                }
            });

            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(loggingInterceptor)
//                    .retryOnConnectionFailure(false)
                    .build();

            sImagePipelineConfig = OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient)
//            sImagePipelineConfig = ImagePipelineConfig.newBuilder(context)
                    .setBitmapsConfig(Bitmap.Config.RGB_565) // 若不是要求忒高清顯示應(yīng)用,就用使用RGB_565吧(默認(rèn)是ARGB_8888)
                    .setDownsampleEnabled(true) // 在解碼時(shí)改變圖片的大小,支持PNG、JPG以及WEBP格式的圖片,與ResizeOptions配合使用
                    // 設(shè)置Jpeg格式的圖片支持漸進(jìn)式顯示
                    .setProgressiveJpegConfig(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);
                        }
                    })
                    .setRequestListeners(requestListeners)
                    .setMemoryTrimmableRegistry(memoryTrimmableRegistry) // 報(bào)內(nèi)存警告時(shí)的監(jiān)聽
                    // 設(shè)置內(nèi)存配置
                    .setBitmapMemoryCacheParamsSupplier(new BitmapMemoryCacheParamsSupplier(
                            (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)))
                    .setMainDiskCacheConfig(mainDiskCacheConfig) // 設(shè)置主磁盤配置
                    .setSmallImageDiskCacheConfig(smallDiskCacheConfig) // 設(shè)置小圖的磁盤配置
                    .build();
        }
        return sImagePipelineConfig;
    }

}

d、替換網(wǎng)絡(luò)實(shí)現(xiàn)為okhttp3

       OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(loggingInterceptor)
//                    .retryOnConnectionFailure(false)
                    .build();

            sImagePipelineConfig = OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient)

e、支持調(diào)試時(shí),顯示圖片加載的Log

   FLog.setMinimumLoggingLevel(FLog.VERBOSE);
   Set<RequestListener> requestListeners = new HashSet<>();
   requestListeners.add(new RequestLoggingListener());

f、內(nèi)存緩存配置完整代碼:

package com.facebook.fresco.helper.config;

import android.app.ActivityManager;
import android.os.Build;

import com.facebook.common.internal.Supplier;
import com.facebook.common.util.ByteConstants;
import com.facebook.fresco.helper.utils.MLog;
import com.facebook.imagepipeline.cache.MemoryCacheParams;

/**
 * 內(nèi)存緩存配置
 * https://github.com/facebook/fresco/issues/738
 *
 * Created by android_ls on 16/9/8.
 */
public class BitmapMemoryCacheParamsSupplier implements Supplier<MemoryCacheParams> {

    private final ActivityManager mActivityManager;

    public BitmapMemoryCacheParamsSupplier(ActivityManager activityManager) {
        mActivityManager = activityManager;
    }

    @Override
    public MemoryCacheParams get() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            return new MemoryCacheParams(getMaxCacheSize(), // 內(nèi)存緩存中總圖片的最大大小,以字節(jié)為單位。
                    56,                                     // 內(nèi)存緩存中圖片的最大數(shù)量。
                    Integer.MAX_VALUE,                      // 內(nèi)存緩存中準(zhǔn)備清除但尚未被刪除的總圖片的最大大小,以字節(jié)為單位。
                    Integer.MAX_VALUE,                      // 內(nèi)存緩存中準(zhǔn)備清除的總圖片的最大數(shù)量。
                    Integer.MAX_VALUE);                     // 內(nèi)存緩存中單個(gè)圖片的最大大小。
        } else {
            return new MemoryCacheParams(
                    getMaxCacheSize(),
                    256,
                    Integer.MAX_VALUE,
                    Integer.MAX_VALUE,
                    Integer.MAX_VALUE);
        }
    }

    private int getMaxCacheSize() {
        final int maxMemory = Math.min(mActivityManager.getMemoryClass() * ByteConstants.MB, Integer.MAX_VALUE);
        MLog.i(String.format("Fresco Max memory [%d] MB", (maxMemory/ByteConstants.MB)));
        if (maxMemory < 32 * ByteConstants.MB) {
            return 4 * ByteConstants.MB;
        } else if (maxMemory < 64 * ByteConstants.MB) {
            return 6 * ByteConstants.MB;
        } else {
            // We don't want to use more ashmem on Gingerbread for now, since it doesn't respond well to
            // native memory pressure (doesn't throw exceptions, crashes app, crashes phone)
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
                return 8 * ByteConstants.MB;
            } else {
                return maxMemory / 4;
            }
        }
    }

}

g、初始化Fresco

Fresco.initialize(context,ImageLoaderConfig.getImagePipelineConfig(context));

二、Fresco的各種使用場(chǎng)景

從網(wǎng)絡(luò)加載一張圖片

String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
ImageLoader.loadImage((SimpleDraweeView)findViewById(R.id.sdv_1), url);

1、顯示一張圖片

    <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/sdv_1"
            android:layout_width="90dp"
            android:layout_height="90dp"
            app:actualImageScaleType="centerCrop"/>

效果圖如下:


2、顯示一張圓形圖片

  <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/sdv_2"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="15dp"
            app:actualImageScaleType="centerCrop"
            app:roundAsCircle="true"/>

效果圖如下:


3、顯示一張圓形帶邊框的圖片

        <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/sdv_3"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="15dp"
            app:actualImageScaleType="centerCrop"
            app:roundAsCircle="true"
            app:roundingBorderColor="#fff3cf44"
            app:roundingBorderWidth="2dp"/>

效果圖如下:


4、顯示一張圓角圖片

   <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/sdv_4"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="15dp"
            app:actualImageScaleType="centerCrop"
            app:roundAsCircle="false"
            app:roundedCornerRadius="10dp"/>

效果圖如下:


5、顯示一張底部是圓角的圖片

   <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/sdv_5"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="15dp"
            app:actualImageScaleType="centerCrop"
            app:roundAsCircle="false"
            app:roundedCornerRadius="10dp"
            app:roundTopLeft="false"
            app:roundTopRight="false"
            app:roundBottomLeft="true"
            app:roundBottomRight="true"/>

效果圖如下:


6、顯示一張左上和右下是圓角的圖片

     <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/sdv_6"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="15dp"
            app:actualImageScaleType="centerCrop"
            app:roundAsCircle="false"
            app:roundedCornerRadius="10dp"
            app:roundTopLeft="true"
            app:roundTopRight="false"
            app:roundBottomLeft="false"
            app:roundBottomRight="true"/>

效果圖如下:


7、設(shè)置占位圖

<com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/sdv_7"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="15dp"
            app:actualImageScaleType="centerCrop"
            app:placeholderImage="@mipmap/ic_launcher"
            app:placeholderImageScaleType="centerCrop" />

8、帶動(dòng)畫的顯示(從半透明到不透明)

 <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/sdv_8"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="15dp"
            app:actualImageScaleType="centerCrop"
            app:fadeDuration="3000"/>

9、圖層疊加顯示

 <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/sdv_10"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="15dp"
            app:actualImageScaleType="centerCrop"
            app:overlayImage="@mipmap/ic_launcher"/>

10、其它的屬性的配置,比如加載進(jìn)度、加載失敗、重試圖

   <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/sdv_11"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_marginTop="15dp"
            app:actualImageScaleType="centerCrop"
            app:failureImage="@mipmap/ic_launcher"
            app:failureImageScaleType="centerInside"
            app:retryImage="@mipmap/ic_launcher"
            app:retryImageScaleType="centerCrop"
            app:progressBarImage="@mipmap/ic_launcher"
            app:progressBarImageScaleType="centerCrop"
            app:progressBarAutoRotateInterval="5000"/>

11、從本地文件(比如SDCard上)加載圖片

  public static void loadFile(final SimpleDraweeView draweeView, String filePath, final int reqWidth, final int reqHeight) {
        Uri uri = new Uri.Builder()
                .scheme(UriUtil.LOCAL_FILE_SCHEME)
                .path(filePath)
                .build();
        ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
                .setRotationOptions(RotationOptions.autoRotate())
                .setLocalThumbnailPreviewsEnabled(true)
                .setResizeOptions(new ResizeOptions(reqWidth, reqHeight))
                .build();
        DraweeController controller = Fresco.newDraweeControllerBuilder()
                .setImageRequest(request)
                .setOldController(draweeView.getController())
                .setControllerListener(new BaseControllerListener<ImageInfo>() {
                    @Override
                    public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable anim) {
                        if (imageInfo == null) {
                            return;
                        }

                        ViewGroup.LayoutParams vp = draweeView.getLayoutParams();
                        vp.width = reqWidth;
                        vp.height = reqHeight;
                        draweeView.requestLayout();
                    }
                })
                .build();
        draweeView.setController(controller);
    }

使用:

ImageLoader.loadFile((SimpleDraweeView)itemView, photoInfo.thumbnailUrl, 120, 120);

12、從本地資源(Resources)加載圖片

  public static void loadDrawable(SimpleDraweeView draweeView, int resId) {
        Uri uri = new Uri.Builder()
                .scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
                .path(String.valueOf(resId))
                .build();
        DraweeController controller = Fresco.newDraweeControllerBuilder()
                .setUri(uri)
                .setOldController(draweeView.getController())
                .build();
        draweeView.setController(controller);
    }

使用:

ImageLoader.loadDrawable(simpleDraweeView, R.drawable.meizi);

效果圖如下:


13、對(duì)圖片進(jìn)行性高斯模糊處理

public static void loadImageBlur(final SimpleDraweeView draweeView, String url) {
        loadImage(draweeView, url, new BasePostprocessor() {
            @Override
            public String getName() {
                return "blurPostprocessor";
            }

            @Override
            public void process(Bitmap bitmap) {
                BitmapBlurHelper.blur(bitmap, 35);
            }
        });
    }

其內(nèi)部調(diào)用的方法

public static void loadImage(SimpleDraweeView simpleDraweeView, String url, BasePostprocessor processor) {
        if (TextUtils.isEmpty(url)) {
            return;
        }

        Uri uri = Uri.parse(url);
        ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
                .setRotationOptions(RotationOptions.autoRotate())
                .setPostprocessor(processor)
                .build();
        DraweeController controller = Fresco.newDraweeControllerBuilder()
                .setImageRequest(request)
                .setOldController(simpleDraweeView.getController())
                .build();
        simpleDraweeView.setController(controller);
    }

使用:

  String url = "http://a.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d3de795ad0628535e4dd6fe2.jpg";

  SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
  
  simpleDraweeView.setAspectRatio(0.7f);
  
  ViewGroup.LayoutParams lvp = simpleDraweeView.getLayoutParams();
  lvp.width = DensityUtil.getDisplayWidth(this);

  ImageLoader.loadImageBlur(simpleDraweeView, url,
                DensityUtil.getDisplayWidth(this), DensityUtil.getDisplayHeight(this));

效果圖如下:


14、我們知道使用Fresco加載并顯示一張圖片,需要指定SimpleDraweeView的寬高或者指定其中一個(gè)值并設(shè)置寬高比,可是我真的不知道要顯示的圖片有多大,該顯示多大?可以幫我搞定嗎?答案是肯定的。

        String url = "http://feed.chujianapp.com/20161108/452ab5752287a99a1b5387e2cd849006.jpg@1080w";
        SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
        ImageLoader.loadImage(simpleDraweeView, url, new SingleImageControllerListener(simpleDraweeView));
        

15、從網(wǎng)絡(luò)加載并顯示gif格式的圖片

   String url = "http://img4.178.com/acg1/201506/227753817857/227754566617.gif";

   SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
   ImageLoader.loadImage(simpleDraweeView, url);

16、加載并顯示webp格式的圖片

        SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
        ViewGroup.LayoutParams lvp = simpleDraweeView.getLayoutParams();
        lvp.width = DensityUtil.getDisplayWidth(this);
        simpleDraweeView.setAspectRatio(0.6f); // 設(shè)置寬高比

        ImageLoader.loadDrawable(simpleDraweeView, R.drawable.meizi_webp,
                DensityUtil.getDisplayWidth(this), DensityUtil.getDisplayHeight(this));

其中R.drawable.meizi_webp為meizi_webp.webp

17、從內(nèi)存緩存中移除指定圖片的緩存

           if (!TextUtils.isEmpty(photoInfo.originalUrl)) {
                ImagePipeline imagePipeline = Fresco.getImagePipeline();
                Uri uri = Uri.parse(photoInfo.originalUrl);
                if (imagePipeline.isInBitmapMemoryCache(uri)) {
                    imagePipeline.evictFromMemoryCache(uri);
                }
            }

18、從磁盤緩存中移除指定圖片的緩存

        ImagePipeline imagePipeline = Fresco.getImagePipeline();
        Uri uri = Uri.parse(photoInfo.originalUrl);
        // 下面的操作是異步的
        if (imagePipeline.isInDiskCacheSync(uri)) {
            imagePipeline.evictFromDiskCache(uri);
        }

19、清空磁盤緩存

Fresco.getImagePipeline().clearDiskCaches();

20、清空內(nèi)存緩存

Fresco.getImagePipeline().clearMemoryCaches();

21、清空緩存(內(nèi)存緩存 + 磁盤緩存)

Fresco.getImagePipeline().clearCaches();

22、在列表視圖滾動(dòng)時(shí),不加載圖片,等滾動(dòng)停止后再開始加載圖片,提升列表視圖的滾動(dòng)流暢度。

    // 需要暫停網(wǎng)絡(luò)請(qǐng)求時(shí)調(diào)用
    public static void pause(){
        Fresco.getImagePipeline().pause();
    }

    // 需要恢復(fù)網(wǎng)絡(luò)請(qǐng)求時(shí)調(diào)用
    public static void resume(){
        Fresco.getImagePipeline().resume();
    }

23、下載圖片存儲(chǔ)到指定的路徑

  /**
     * 從網(wǎng)絡(luò)下載圖片
     * 1、根據(jù)提供的圖片URL,獲取圖片數(shù)據(jù)流
     * 2、將得到的數(shù)據(jù)流寫入指定路徑的本地文件
     *
     * @param url            URL
     * @param loadFileResult LoadFileResult
     */
    public static void downloadImage(Context context, String url, final DownloadImageResult loadFileResult) {
        if (TextUtils.isEmpty(url)) {
            return;
        }

        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() || loadFileResult == null) {
                    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);
                        String photoPath = loadFileResult.getFilePath();
                        Log.i("ImageLoader", "photoPath = " + photoPath);

                        byte[] data = StreamTool.read(inputStream);
                        StreamTool.write(photoPath, data);
                        loadFileResult.onResult(photoPath);
                    } catch (IOException e) {
                        loadFileResult.onFail();
                        e.printStackTrace();
                    } finally {
                        imageReference.close();
                        closeableReference.close();
                    }
                }
            }

            @Override
            public void onFailureImpl(DataSource dataSource) {
                if (loadFileResult != null) {
                    loadFileResult.onFail();
                }

                Throwable throwable = dataSource.getFailureCause();
                if (throwable != null) {
                    Log.e("ImageLoader", "onFailureImpl = " + throwable.toString());
                }
            }
        }, Executors.newSingleThreadExecutor());
    }

使用:

    String url = "http://feed.chujianapp.com/20161108/452ab5752287a99a1b5387e2cd849006.jpg@1080w";
    String filePath = "";
    ImageLoader.downloadImage(context, url, new DownloadImageResult(filePath) {

        @Override
        public void onResult(String filePath) {

        }

        @Override
        public void onFail() {

        }
    });

24、不使用SimpleDraweeView組件,但是想使用Fresco去加載圖片(兩級(jí)內(nèi)存緩存+磁盤緩存要有)并顯示到其他組件上(比如顯示在TextView的drawableLeft屬性上或者顯示為View的背景)。

public static void loadTextDrawable(final TextView view, String url, final int direction, final int iconWidth, final int iconHeight) {
        ImageLoader.loadImage(view.getContext(), url, new LoadImageResult() {
            @Override
            public void onResult(Bitmap bitmap) {
                Drawable drawable = new BitmapDrawable(view.getContext().getResources(), bitmap);
                final int width = DensityUtil.dipToPixels(view.getContext(), iconWidth);
                final int height = DensityUtil.dipToPixels(view.getContext(), iconHeight);
                drawable.setBounds(0, 0, width, height);
                switch (direction) {
                    case 0:
                        view.setCompoundDrawables(drawable, null, null, null);
                        break;
                    case 1:
                        view.setCompoundDrawables(null, drawable, null, null);
                        break;
                    case 2:
                        view.setCompoundDrawables(null, null, drawable, null);
                        break;
                    case 3:
                        view.setCompoundDrawables(null, null, null, drawable);
                        break;
                }
            }
        });
    }

三、推薦的使用方法

1、第一種用法

初始化

 Phoenix.init(this); // Context

從網(wǎng)絡(luò)加載一張圖片

String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
Phoenix.with(simpleDraweeView).load(url);

從本地加載一張圖片

String filePath = "/sdcard/image/test.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
Phoenix.with(simpleDraweeView).load(filePath);

從res下面加載一張圖片

SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
Phoenix.with(simpleDraweeView).load(R.drawable.meizi);

在寫布局文件xml時(shí),我不知道要顯示的圖片尺寸,需要根據(jù)業(yè)務(wù)邏輯動(dòng)態(tài)的設(shè)置要顯示的圖片的大小,可以像下面這樣寫:

String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
Phoenix.with(simpleDraweeView)
       .setWidth(100)
       .setHeight(100)
       .load(url);

只知道要顯示圖片的高或者寬的值,另一個(gè)值可以從設(shè)置的比例得出

String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
Phoenix.with(simpleDraweeView)
       .setWidth(100)
       .setAspectRatio(0.6f) // w/h = 6/10
       .load(url);

圖片的高斯模糊處理

String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
Phoenix.with(simpleDraweeView)
       .setNeedBlur(true)
       .load(url);

加載并顯示gif格式的圖片

String url = "http://img4.178.com/acg1/201506/227753817857/227754566617.gif";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
Phoenix.with(simpleDraweeView)
       .load(url);

加載并顯示webp格式的圖片

SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
Phoenix.with(simpleDraweeView)
        .load(R.drawable.meizi_webp);

......

2、第二種用法

初始化

 Fresco.initialize(context, ImageLoaderConfig.getImagePipelineConfig(context));

從網(wǎng)絡(luò)加載一張圖片

String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
ImageLoader.loadImage(simpleDraweeView, url);

從本地加載一張圖片

String filePath = "/sdcard/image/test.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
ImageLoader.loadFile(simpleDraweeView, filePath);

從res下面加載一張圖片

SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
ImageLoader.loadDrawable(simpleDraweeView, R.drawable.meizi, 100, 100);

在寫布局文件xml時(shí),我不知道要顯示的圖片尺寸,需要根據(jù)業(yè)務(wù)邏輯動(dòng)態(tài)的設(shè)置要顯示的圖片的大小,可以像下面這樣寫:

String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
ImageLoader.loadImage(simpleDraweeView, url, 120, 120);

只知道要顯示圖片的高或者寬的值,另一個(gè)值可以從設(shè)置的比例得出

String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
ViewGroup.LayoutParams lvp = simpleDraweeView.getLayoutParams();
lvp.width = DensityUtil.getDisplayWidth(this); // 取值為手機(jī)屏幕的寬度
simpleDraweeView.setAspectRatio(0.6f); // 設(shè)置寬高比
ImageLoader.loadDrawable(simpleDraweeView, R.drawable.meizi);

圖片的高斯模糊處理

String url = "http://ww3.sinaimg.cn/large/610dc034jw1f6m4aj83g9j20zk1hcww3.jpg";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
ImageLoader.loadImageBlur(simpleDraweeView, url);

加載并顯示gif格式的圖片

String url = "http://img4.178.com/acg1/201506/227753817857/227754566617.gif";
SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
ImageLoader.loadImage(simpleDraweeView, url);

加載并顯示webp格式的圖片

SimpleDraweeView simpleDraweeView = (SimpleDraweeView)findViewById(R.id.sdv_1);
ImageLoader.loadDrawable(simpleDraweeView, R.drawable.meizi_webp);

......

3、大圖瀏覽器
帶動(dòng)畫的效果打開方式,詳細(xì)細(xì)節(jié)請(qǐng)查看PhotoWallActivity中的使用

 ArrayList<PhotoInfo> photos = null;
 PictureBrowse.newBuilder(PhotoWallActivity.this)
              .setParentView(parent)
              .setCurrentPosition(position)
              .setPhotoList(photos)
              .enabledAnimation(true)
              .build()
              .start();

無(wú)動(dòng)畫效果的打開方式

 ArrayList<PhotoInfo> photos = null;
 PictureBrowse.newBuilder(PhotoWallActivity.this)
              .setParentView(parent)
              .setCurrentPosition(position)
              .setPhotoList(photos)
              .build()
              .start();

我提供了兩種圖片加載使用方式,你想使用那種圖片加載方式,全看個(gè)人愛好(推薦使用第一種方式)。

代碼我已上傳到github上了,地址:https://github.com/hpdx/fresco-helper

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評(píng)論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,238評(píng)論 3 428
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,339評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,713評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評(píng)論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,893評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,448評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,201評(píng)論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,397評(píng)論 1 372
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,631評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評(píng)論 1 293
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,128評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,347評(píng)論 2 377

推薦閱讀更多精彩內(nèi)容