Fresco-Facebook的圖片加載框架的使用

目前經常使用的開源圖片加載框架有:1.Universal-Image-Loader,該項目存在於Github上面https://github.com/nostra13/Android-Universal-Image-Loaderjava

2.fresco,該項目的中文網站是:http://www.fresco-cn.org/,在Github上面是:https://github.com/facebook/frescoandroid

以前一直用的是Universal-Image-Loader,改用fresco以後,在有大圖展現的頁面,能明顯感受到fresco在渲染速度和圖片呈現效果上更勝一籌。fresco與Universal-Image-Loader比起來,最直觀的幾個優勢是:
1.在顯示圓形、圓角圖片時,不須要另行引入CircleImageView等第三方或者自定義控件;
2.更容易實現圖片View的點擊效果;
3.默認的漸入顯示效果;git

下面來講一下fresco的使用:github

1.若是使用的是Android Studio,則須要在build.gradle中引入fresco項目:web

[java] view plain copy
  1. dependencies {  
  2. ......  
  3. compile 'com.facebook.fresco:fresco:0.9.0+'  
  4. ......  

其中0.9.0是fresco的版本;緩存

2.在程序顯示圖片以前調用init接口,通常會在Application的onCreate方法中調用Fresco.initialize()方法,該方法有兩種傳參方式:網絡

[java] view plain copy
  1. /** Initializes Fresco with the default config. */  
  2. public static void initialize(Context context)  
  3.   
  4. /** Initializes Fresco with the specified config. */  
  5. public static void initialize(Context context, ImagePipelineConfig imagePipelineConfig)  


其中不對ImagePipeline進行配置的話,Fresco將採用默認的配置。ImagePipelineConfig能夠進行以下配置:app

[java] view plain copy
  1. public ImagePipelineConfig getImagePipelineConfig() {  
  2.     ImagePipelineConfig config = ImagePipelineConfig.newBuilder(App.getAppContext())  
  3.             .setWebpSupportEnabled(true)  
  4.                     /** 
  5.                      * 必須和ImageRequest的ResizeOptions一塊兒使用,做用就是在圖片解碼時根據ResizeOptions所設的寬高的像素進行解碼,這樣解碼出來能夠獲得一個更小的Bitmap。ResizeOptions和DownsampleEnabled參數都不影響原圖片的大小,影響的是EncodeImage的大小,進而影響Decode出來的Bitmap的大小,ResizeOptions須和此參數結合使用是由於單獨使用ResizeOptions的話只支持JPEG圖,因此需支持png、jpg、webp須要先設置此參數。 
  6.                      */  
  7.             .setDownsampleEnabled(true)  
  8.                     /** 
  9.                      * 最終影響的是mDownsampleEnabledForNetwork參數。 這個參數的做用是在mDownsampleEnabled爲true的狀況下,設置是否當此次請求是從網絡中加載圖片時,來對三級緩存中的編碼圖片從新改變大小。 
  10.                      */  
  11.             .setResizeAndRotateEnabledForNetwork(true)  
  12.                     /** 
  13.                      * 是否根據不一樣的平臺來構建相應的解碼器 
  14.                      */  
  15.             .setDecodeMemoryFileEnabled(true)  
  16.                     /** 
  17.                      * 所加載圖片的配置,默認爲Bitmap.Config.ARGB_8888 
  18.                      */  
  19.             .setBitmapsConfig(Bitmap.Config config)  
  20.                     /** 
  21.                      * 三級緩存中已解碼圖片的內存緩存配置 
  22.                      */  
  23.             .setBitmapMemoryCacheParamsSupplier(bitmapCacheParamsSupplier)  
  24.                     /** 
  25.                      * 三級緩存中編碼圖片的內存緩存 
  26.                      */  
  27.             .setEncodedMemoryCacheParamsSupplier(encodedCacheParamsSupplier)  
  28.                     /** 
  29.                      * 三級緩存中硬盤緩存的配置,默認緩存目錄在app自身CacheDir的image_cache目錄下 
  30.                      */  
  31.             .setMainDiskCacheConfig(mainDiskCacheConfig)  
  32.                     /** 
  33.                      * 執行各個任務的線程池配置,包括配置執行IO任務、後臺任務、優先級低的後臺任務、Decode任務的線程池的配置。 
  34.                      */  
  35.             .setExecutorSupplier(executorSupplier)  
  36.                     /** 
  37.                      * 緩存的統計數據追蹤器。它是一個接口,提供了各個緩存中圖片Hit與Miss的回調方法,一般可使用它來統計緩存命中率 
  38.                      */  
  39.             .setImageCacheStatsTracker(imageCacheStatsTracker)  
  40.                     /** 
  41.                      * 註冊一個內存調節器,它將根據不一樣的MemoryTrimType回收類型在須要下降內存使用時候進行回收一些內存緩存資源(Bitmap和Encode)。數值越大,表示要回收的資源越多。 
  42.                      */  
  43.             .setMemoryTrimmableRegistry(memoryTrimmableRegistry)  
  44.                     /** 
  45.                      * 網絡圖片下載請求類 
  46.                      */  
  47.             .setNetworkFetchProducer(networkFetchProducer)  
  48.                     /** 
  49.                      * 漸進式顯示網絡的JPEG圖的配置,不過要使用漸進式顯示圖片,須要在ImageRequest中顯示的設置是否支持漸進式顯示:setProgressiveRenderingEnabled(true) 
  50.                      */  
  51.             .setProgressiveJpegConfig(progressiveJpegConfig)  
  52.                     /** 
  53.                      * 小圖的硬盤緩存配置,默認是和主硬盤緩存目錄是共用的。若是須要把小圖和普通圖片分開,則需從新配置。 
  54.                      */  
  55.             .setSmallImageDiskCacheConfig(smallImageDiskCacheConfig)  
  56.             .build();  
  57.     return config;  
  58. }  

這裏要介紹一下fresco的三級緩存:Bitmap緩存+編碼/未解碼圖片緩存+硬盤緩存。Fresco的加載圖片的流程爲:查找Bitmap緩存中是否存在,存在則直接返回Bitmap直接使用,不存在則查找未解碼圖片的緩存,若是存在則進行Decode成Bitmap而後直接使用並加入Bitmap緩存中,若是未解碼圖片緩存中查找不到,則進行硬盤緩存的檢查,若有,則進行IO、轉化、解碼等一系列操做,最後成Bitmap供咱們直接使用,並把未解碼(Encode)的圖片加入未解碼圖片緩存,把Bitmap加入Bitmap緩存中,如硬盤緩存中沒有,則進行Network操做下載圖片,而後加入到各個緩存中。ImagePipelineConfig及fresco的緩存原理詳見:http://blog.csdn.net/u010687392/article/details/50266633框架

3.使用com.facebook.drawee.view.SimpleDraweeView替換掉ImageView。SimpleDraweeView能夠經過配置實現圓形、圓角、pressed效果、默認圖片、加載失敗圖片等顯示效果,在佈局中能夠以下配置(以圓形效果爲例):ide

[java] view plain copy
  1. <com.facebook.drawee.view.SimpleDraweeView  
  2.     android:id="@+id/iv_user_avatar"  
  3.     android:layout_width="@dimen/common_big_user_portrait_height"  
  4.     android:layout_height="@dimen/common_big_user_portrait_height"  
  5.     android:layout_centerInParent="true"  
  6.     /** 正常圖片的ScaleType*/  
  7.     fresco:actualImageScaleType="centerCrop"  
  8.     /**圖片加載失敗時的圖片及其ScaleType*/  
  9.     fresco:failureImage="@drawable/default_user_portrait"  
  10.     fresco:failureImageScaleType="centerCrop"  
  11.     /** 默認圖片及其ScaleType*/  
  12.     fresco:placeholderImage="@drawable/default_user_portrait"  
  13.     fresco:placeholderImageScaleType="centerCrop"  
  14.     /**pressed效果,通常是經過佈局shape一種色值*/  
  15.     fresco:pressedStateOverlayImage="@drawable/common_circle_image_pressed"  
  16.     /**圓形 */  
  17.     fresco:roundAsCircle="true"  
  18.     />  

若是是圓角的話,能夠在上面的基礎上增長以下特殊配置,其中fresco:roundedCornerRadius根據須要具體設置值:

[java] view plain copy
  1. fresco:roundAsCircle="false"  
  2. fresco:roundBottomLeft="true"  
  3. fresco:roundBottomRight="true"  
  4. fresco:roundTopLeft="true"  
  5. fresco:roundTopRight="true"  
  6. fresco:roundedCornerRadius="xdp"  

而後在代碼中,調用以下語句便可顯示網絡或者本地圖片:

[java] view plain copy
  1. String uri = bean.getUrl();  
  2. if (!uri.startsWith("http")) {  
  3.     uri = "file://" + bean.getUrl();  
  4. }  

若是就是想讓view顯示默認的圖片,則調用語句:

[java] view plain copy
  1. simpleDraweeView.setImageURI(Uri.parse(「」));  

 

若是想修改默認的ImageRequest、DraweeController等的配置,則能夠在代碼中這樣配置和顯示圖片(以顯示圓形圖片爲例):

[java] view plain copy
  1.     public void displayCirclePortraitImage(Context context, String picUrl, SimpleDraweeView iv_pic) {  
  2.         if (iv_pic == null) {  
  3.             return;  
  4.         }  
  5.         Context tempContext = context;  
  6.         if (tempContext == null) {  
  7.             tempContext = App.getAppContext();  
  8.         }  
  9.         if (!StringUtil.isEmpty(picUrl)) {  
  10.             Uri uri = Uri.parse(picUrl);  
  11.             ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)  
  12.                     .setLocalThumbnailPreviewsEnabled(true)  
  13.                     .setAutoRotateEnabled(true)  
  14.                     .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH)  
  15.                     .setProgressiveRenderingEnabled(false)  
  16.                     .build();  
  17.             DraweeController controller = Fresco.newDraweeControllerBuilder()  
  18.                     .setImageRequest(request)  
  19.                     .setAutoPlayAnimations(true)  
  20.                     .setOldController(iv_pic.getController())  
  21.                     .build();  
  22.             iv_pic.setController(controller);  
  23.         } else {  
  24.             iv_pic.setImageURI(Uri.parse(""));  
  25.         }  
  26. //        GenericDraweeHierarchy ghy = iv_pic.getHierarchy();  
  27. //        if (ghy == null) {  
  28.             GenericDraweeHierarchyBuilder gbulder = new GenericDraweeHierarchyBuilder(tempContext.getResources());  
  29.             ghy = gbulder.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)  
  30.                     .setPlaceholderImage(tempContext.getResources().getDrawable(R.drawable.default_user_portrait), ScalingUtils.ScaleType.CENTER_CROP)  
  31.                     .setFailureImage(tempContext.getResources().getDrawable(R.drawable.default_user_portrait), ScalingUtils.ScaleType.CENTER_CROP)  
  32.                     .setRoundingParams(RoundingParams.asCircle())  
  33.                     .setPressedStateOverlay(tempContext.getResources().getDrawable(R.drawable.common_circle_image_pressed))  
  34.                     .build();  
  35.             iv_pic.setHierarchy(ghy);  
  36. //        } else {  
  37. //            ghy.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP);  
  38. //            ghy.setRoundingParams(RoundingParams.asCircle());  
  39. //        }  
  40.         float scaleRadio = 1.0f;  
  41.         iv_pic.setAspectRatio(scaleRadio);  
  42.     }  

若是隻想下載圖片,不使用SimpleDraweeView控件,則能夠經過以下方法:

[java] view plain copy
  1. public void loadImage(Context context, String picUrl, ResizeOptions resizeOptions, BaseBitmapDataSubscriber bitmapDataSubscriber) {  
  2.     if (StringUtil.isEmpty(picUrl)) {  
  3.         return;  
  4.     }  
  5.     Uri uri = Uri.parse(picUrl);  
  6.     ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(uri)  
  7.             .setLocalThumbnailPreviewsEnabled(true)  
  8.             .setAutoRotateEnabled(true)  
  9.             .setResizeOptions(resizeOptions)  
  10.             .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH)  
  11.             .setProgressiveRenderingEnabled(false)  
  12.             .build();  
  13.   
  14.     ImagePipeline imagePipeline = Fresco.getImagePipeline();  
  15.     DataSource<CloseableReference<CloseableImage>>  
  16.             dataSource = imagePipeline.fetchDecodedImage(imageRequest, context);  
  17.     dataSource.subscribe(bitmapDataSubscriber, CallerThreadExecutor.getInstance());  
  18. }  

其中回調接口BaseBitmapDataSubscriber實現以下:

[java] view plain copy
  1. FrescoImageLoader.getInstance().loadImage(ViewSinglePhotoActivity.this, picUrl, resizeOptions, new  
  2.         BaseBitmapDataSubscriber() {  
  3.             @Override  
  4.             protected void onNewResultImpl(Bitmap bitmap) {  
  5.                 ViewSinglePhotoActivity.this.runOnUiThread(new Runnable() {  
  6.                     @Override  
  7.                     public void run() {  
  8.                         loadPb.setVisibility(View.GONE);  
  9.                     }  
  10.                 });  
  11.                 if (bitmap != null && photoView != null) {  
  12.                     final Bitmap arg2 = Bitmap.createBitmap(bitmap);  
  13.                     ImageCache.getInstance().put(picUrl, arg2);  
  14.                     ViewSinglePhotoActivity.this.runOnUiThread(new Runnable() {  
  15.                         @Override  
  16.                         public void run() {  
  17.                             photoView.setImageBitmap(arg2);  
  18.                         }  
  19.                     });  
  20.                 }  
  21.             }  
  22.   
  23.             @Override  
  24.             protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {  
  25.                 ViewSinglePhotoActivity.this.runOnUiThread(new Runnable() {  
  26.                     @Override  
  27.                     public void run() {  
  28.                         loadPb.setVisibility(View.GONE);  
  29.                         photoView.setImageResource(R.drawable.default_pic);  
  30.                     }  
  31.                 });  
  32.             }  
  33.         });  

注意事項:

1.佈局中若是使用了fresco的屬性,則須要引入命名空間:
xmlns:fresco="http://schemas.android.com/apk/res-auto"

2.SimpleDraweeView不支持wrap_content屬性,必須給出具體的寬高值,若是width或者height其中有一個值爲wrap_content,則能夠經過設置寬高比的方法setAspectRatio間接指定其值;

3.使用SimpleDraweeView後,facebook官方建議不要再使用ImageView的任何屬性,如setImageResource、setBackground、setScaleType等;後續版本SimpleDraweeView旨在改成直接繼承View;

4.GenericDraweeHierarchy的屬性配置要麼在佈局中設置完,要麼在代碼中設置完;simpleDraweeView.getHierarchy()的值一直都不爲空,因此不要用這個判斷條件來作區分;

5.關於OOM,1.請給ImageRequest默認配置上setResizeOptions(resizeOptions)屬性;對於照片牆等含有大量圖片的頁面,必需要對圖片的大小作限制;網絡圖片能夠經過服務端來對圖片的尺寸、質量、圖片類型作處理後再返給客戶端,可是對於手機本地的圖片,就只能經過setResizeOptions來有效下降內存緩存的開銷;2.在低內存的狀況下或者退出多圖頁面的狀況下,手動釋放內存緩存:

[java] view plain copy
  1. ImagePipeline imagePipeline = Fresco.getImagePipeline();  
  2. //清空內存緩存(包括Bitmap緩存和未解碼圖片的緩存)  
  3. imagePipeline.clearMemoryCaches();  
  4. //清空硬盤緩存,通常在設置界面供用戶手動清理  
  5. imagePipeline.clearDiskCaches();  
  6. //同時清理內存緩存和硬盤緩存  
  7. imagePipeline.clearCaches();  

6.BaseBitmapDataSubscriber的方法onNewResultImpl中返回的Bitmap會很快被系統回收掉,因此須要再複製一份自行保存;保存時能夠採用LruCache方法。

7.對於webp格式的網絡圖片內容,若是引入的是fresco:0.6.0;則在安卓4.2.2的手機上沒有問題,若是引入的是fresco:0.8.0或者fresco:0.9.0,則在安卓4.2.2的手機上圖片會加載失敗。

相關文章
相關標籤/搜索