借鑒Glide思想二次封裝Fresco


本篇文章已授權微信公眾號 dasu_Android(大蘇)獨家發布

最近封裝了個 Fresco 的組件庫:DFresco,就順便來講講。

背景

Fresco 圖片庫很強大,我們項目中就是使用的 Fresco,但有一點就是,不怎么好使用,略麻煩。不同項目中,多多少少都需要對 Fresco 進行一層封裝才能在 ui 里快速使用。

這就導致了,不同項目都根據自己的業務需求場景來進行封裝,每次有新項目,復制粘貼時又得解決好多業務耦合的錯誤,麻煩,是真的麻煩~

而且,首次接觸 Fresco,接入上手的成本相比其他圖片庫,如 Glide,成本都要大很多。

舉個例子,假如你有這么個需求:加載一張網絡上的 gif 圖片,為了防止內存占用過多,需要設置分辨率壓縮,最后顯示到圓形控件上,同時,需要設置占位圖,錯誤圖,拉伸方式等。

那么此時,你的代碼可能就是這樣的:

ImageDecodeOptions imageDecodeOptions = ImageDecodeOptions.newBuilder()
    	.setDecodePreviewFrame(true).build();
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(mUri)
   		.setProgressiveRenderingEnabled(true)
    	.setImageDecodeOptions(imageDecodeOptions);
if (mWidth > 0 && mHeight > 0) {
    builder.setResizeOptions(new ResizeOptions(mWidth, mHeight));
}

ImageRequest request = builder.build();
AbstractDraweeController controller = Fresco.newDraweeControllerBuilder()
    		.setImageRequest(request)
   		 	.setControllerListener(listener)
    		.setOldController(draweeView.getController())
    		.setAutoPlayAnimations(true).build();
draweeView.setController(controller);

同時,你可能還需要在 xml 中對 SimpleDrawwView 控件進行占位圖等等的配置:

<com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/sdv_fresco"
        android:layout_width="500dp"
        android:layout_height="500dp"
        fresco:actualImageScaleType="centerCrop"
        fresco:fadeDuration="3000"
        fresco:failureImage="@mipmap/ic_launcher"
        fresco:failureImageScaleType="centerCrop"
        fresco:placeholderImage="@mipmap/ic_launcher"
        fresco:placeholderImageScaleType="centerCrop"
        fresco:progressBarAutoRotateInterval="1000"
        fresco:progressBarImage="@drawable/ani_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:roundingBorderWidth="2dip"
        fresco:roundingBorderColor="@color/colorPrimary"/>

如果忘記了某個自定義屬性名是什么的時候,還得到網上搜索下資料,是吧。

小結一下,使用 Fresco,你的接入學習成本至少需要知道 Fresco 的如下信息:

  • SimpleDraweeView 的自定義屬性
  • ImageRequestBuilder 用法及大概用途
  • AbstractDraweeController 用法及大概用途
  • GenericDraweeHierarchy 用法及大概用途

如果涉及到一些網絡下載監聽,緩存之類的,那么你還要了解:

  • Imagepipeline 用法及大概用途

總之,Fresco 強大是強大,但使用起來不方便,不得不封裝一層。

既然要封裝,那么就直接借鑒 Glide 的使用思想來進行封裝好了,如果有使用過 Glide 的應該很清楚,要實現以上功能,全程一個調用鏈即可。

二次封裝

封裝要達到的目的有兩點:

  • 使用簡潔、方便
  • 其他人接入直接上手的成本盡可能少,最好不用去看文檔,去看源碼

第一點可以參考 Glide 的使用方式來設計,那么第二點我的想法是借助 AndroidStudio 的代碼提示功能來實現。

比如,你只需知道,組件的入口是 DFresco 即可,其他都通過 AndroidStudio 來給你提示,如:

Dfresco入口.png

當你在 AndroidStudio 上輸入 DFresco. 后,界面上會彈出你可用 api,這些就是我開放給你的入口,我將這個使用過程划分成幾個步驟,每個步驟能做什么,該做什么,我都給你規定好了,你參照着提示,直接從方法命名上就能夠知道該如何使用了,AndroidStudio 會一步步引導你。

這里就兩個入口,一個是用來初始化 Fresco 的:

  • init(Context)

這個內部封裝了一些默認的初始化配置,比如內存大小配置,內部日志配置等等。

  • init(Context, ImagePipelineConfig)

這個是開放給你的自定義配置,如果你不想使用默認的配置的話。

  • source(String url) :加載網絡上的圖片
  • source(File localFile) :加載磁盤上的圖片
  • source(Context context, int resId) :加載 res 內的 drawable 資源圖片
  • source(Uri uri) :通用的加載方式

我將常用的幾種圖片來源單獨封裝出來使用,方便。

DFresco第二步.png

當調用了 source() 后就進入了第二個步驟,這個步驟中,我將圖片相關的配置設計到另外一個步驟中去,否則連同圖片配置的 api 也都在這里的話,會搞得蠻亂的,可能讓使用者到這里后不清楚該調用哪些接口了。

所以,我會把控每個步驟的 api,盡量讓每個步驟的 api 做的事都比較相近,比如這里:

  • intoTarget(SimpleDraweeView) 加載圖片顯示到控件上
  • intoTarget(SimpleDraweeView,ControllerListener) 加載圖片顯示到控件上,允許監聽這個過程
  • intoTarget(BaseBitmapDataSubscriber) 只加載圖片到內存中,以 Bitmap 形式存在

我的需求場景大概就是直接加載圖片顯示到控件上,或者有時候只是需要將圖片加載到內存中,但不用顯示到某個控件上,反而要取得圖片的 Bitmap 對象,所以我將這些都封裝起來了。

  • resize(int width, int height)

這個實際上就是對 Fresco 中的 ResizeOptions 的一層封裝而已,簡化使用,不至於像以前那么麻煩。

  • enterImageConfig()

如果你都使用默認配置的話,那么是不用再去調用那些各種配置的接口的,所以我才將圖片配置封裝到另外一個步驟中,這個步驟你可進,可不進,如果有需求,那么通過這個方法進入圖片配置步驟:

ImageConfig.png

這里的配置項很多,也是因為這個原因,所以才不想讓這些接口跟上一個步驟放一起,不然很容易讓使用者懵掉。而進入了圖片配置這個步驟后,這里提供的 api 其實就是對 GenericDraweeHierarchy 的用途進行了一層封裝,或者說對 SimpleDraweeView 的自定義屬性進行了一層封裝。

如果你不熟悉,沒關系,其實就是一些常用的功能,如設置控件為圓形、圓角、邊框,設置占位圖、失敗圖、進度圖、圖片拉伸方式、淡入淡出動畫時長等等。

這樣封裝的目的在於,你可以通過一條調用鏈的形式就設置完所有的配置,就像 Glide 的使用一樣,而不用再去 new 很多 Fresco 的類,再去拼接。

進入圖片配置步驟只是一個可選的步驟,進來之后當然就要出去,所以當完成了你的配置后,需要調用:finishImageConfig(),如:

第三部.png

這樣就完成了圖片配置,將流程切回主線了,就可以繼續根據你的需要設置圖片顯示的目標了。

當然,為了防止再次進入圖片配置步驟這樣造成之前的配置項失效的場景,我借鑒了 Fresco 的 init 處理方法,即,如果一次使用過程中,重復進入圖片配置步驟,那么程序會拋異常來提醒你不能這么做。

以上,就是 DFresco 組件的封裝思想,歡迎指點一下哈~

另外,參考了 Glide 的一些處理,當你的 intoTarget 是傳入了 SimpleDraweeView 控件時,DFresco 內部會自動根據控件的大小對圖片進行一次分辨率壓縮,降低圖片占用內存,當然,如果你有手動調用了 resize(),那么以你的為主。

使用示例

compile 'com.dasu.image:fresco:0.0.1'

使用之前,需先初始化,建議在 Application 中進行:

DFresco.init(this);
//加載 res 中的 drawable 圖片到 SimpleDraweeView 控件上(默認支持 gif 圖,並且會自動根據控件寬高進行分辨率壓縮,降低內存占用
DFresco.source(mContext, R.drawable.weixin).intoTarget(mSimpleDraweeView);

//加載磁盤中的圖片,手動設置分辨率的壓縮,並獲取 bitmap 對象,監聽回調,手動顯示到 ImageView 控件上
DFresco.source(new File("/mnt/sdcard/weixin.jpg"))
        .resize(500, 500)
        .intoTarget(new BaseBitmapDataSubscriber() {
                @Override
                protected void onNewResultImpl(Bitmap bitmap) {
                    Log.w("!!!!!!", "bitmap:ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount());
                    Log.w("!!!!!!", "width:" + bitmap.getWidth() + ":::height:" + bitmap.getHeight());
                    mImageView.setImageBitmap(bitmap);
                }

                @Override
                protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
                    Log.e("!!!!!!", "onFailureImpl");
                }
            });

//加載網絡圖片,進行各種配置,如縮放方式,占位圖,圓形,圓角,動畫時長等等,最后自動顯示到 SimpleDraweeView 控件上
DFresco.source("https://upload-images.jianshu.io/upload_images/1924341-9e528ee638e837a5.png")
                    .enterImageConfig() //進入配置步驟
                    .allFitXY()  //所有圖片,包括占位圖等等的拉伸方式
                    .animFade(3000) //淡入淡出動畫時長
                    .placeholderScaleType(ScalingUtils.ScaleType.CENTER_INSIDE) //設置占位圖的拉伸方式,后面設置的會覆蓋前面的
                    .actualScaleType(ScalingUtils.ScaleType.CENTER)
//                    .asRound(50) //設置圓角,(圓角和圓形不能同時設置)
                    .asCircle() //設置控件顯示為圓形控件
                    .roundBorderColor(Color.RED) //設置圓角或圓形的邊框顏色
                    .roundBorderWidth(20)  //設置圓角或圓形的邊框寬度
                    .failure(R.drawable.timg) //設置失敗圖
                    .progressBar(R.drawable.aaaa) //設置加載進度圖
                    .retry(R.drawable.weixin) //設置重試時的圖
                    .placeholder(R.drawable.image) //設置占位圖
                    .finishImageConfig() //退出配置步驟
                    .intoTarget(mSimpleDraweeView);

Github 地址

DFresco:https://github.com/woshidasusu/base-module/tree/master/fresco


大家好,我是 dasu,歡迎關注我的公眾號(dasuAndroidTv),如果你覺得本篇內容有幫助到你,可以轉載但記得要關注,要標明原文哦,謝謝支持~
dasuAndroidTv2.png


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM