本篇文章已授权微信公众号 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 来给你提示,如:

当你在 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) :通用的加载方式

我将常用的几种图片来源单独封装出来使用,方便。

当调用了 source() 后就进入了第二个步骤,这个步骤中,我将图片相关的配置设计到另外一个步骤中去,否则连同图片配置的 api 也都在这里的话,会搞得蛮乱的,可能让使用者到这里后不清楚该调用哪些接口了。

所以,我会把控每个步骤的 api,尽量让每个步骤的 api 做的事都比较相近,比如这里:

  • intoTarget(SimpleDraweeView) 加载图片显示到控件上
  • intoTarget(SimpleDraweeView,ControllerListener) 加载图片显示到控件上,允许监听这个过程
  • intoTarget(BaseBitmapDataSubscriber) 只加载图片到内存中,以 Bitmap 形式存在

我的需求场景大概就是直接加载图片显示到控件上,或者有时候只是需要将图片加载到内存中,但不用显示到某个控件上,反而要取得图片的 Bitmap 对象,所以我将这些都封装起来了。

  • resize(int width, int height)

这个实际上就是对 Fresco 中的 ResizeOptions 的一层封装而已,简化使用,不至于像以前那么麻烦。

  • enterImageConfig()

如果你都使用默认配置的话,那么是不用再去调用那些各种配置的接口的,所以我才将图片配置封装到另外一个步骤中,这个步骤你可进,可不进,如果有需求,那么通过这个方法进入图片配置步骤:

这里的配置项很多,也是因为这个原因,所以才不想让这些接口跟上一个步骤放一起,不然很容易让使用者懵掉。而进入了图片配置这个步骤后,这里提供的 api 其实就是对 GenericDraweeHierarchy 的用途进行了一层封装,或者说对 SimpleDraweeView 的自定义属性进行了一层封装。

如果你不熟悉,没关系,其实就是一些常用的功能,如设置控件为圆形、圆角、边框,设置占位图、失败图、进度图、图片拉伸方式、淡入淡出动画时长等等。

这样封装的目的在于,你可以通过一条调用链的形式就设置完所有的配置,就像 Glide 的使用一样,而不用再去 new 很多 Fresco 的类,再去拼接。

进入图片配置步骤只是一个可选的步骤,进来之后当然就要出去,所以当完成了你的配置后,需要调用:finishImageConfig(),如:

这样就完成了图片配置,将流程切回主线了,就可以继续根据你的需要设置图片显示的目标了。

当然,为了防止再次进入图片配置步骤这样造成之前的配置项失效的场景,我借鉴了 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),如果你觉得本篇内容有帮助到你,可以转载但记得要关注,要标明原文哦,谢谢支持~

借鉴Glide思想二次封装Fresco的更多相关文章

  1. Glide二次封装库的使用

    更多代码可以查询本人GitHub:欢迎阅读,star点起来. Glide二次封装库源码 前言 为什么选择Glide? Glide 轻量级 速度快 可以根据所需加载图片的大小自动适配所需分辨率的图 支持 ...

  2. .Net Framework下对Dapper二次封装迁移到.Net Core2.0遇到的问题以及对Dapper的封装介绍

    今天成功把.Net Framework下使用Dapper进行封装的ORM成功迁移到.Net Core 2.0上,在迁移的过程中也遇到一些很有意思的问题,值得和大家分享一下.下面我会还原迁移的每一个过程 ...

  3. 毕加索的艺术——Picasso,一个强大的Android图片下载缓存库,OkHttpUtils的使用,二次封装PicassoUtils实现微信精选

    毕加索的艺术--Picasso,一个强大的Android图片下载缓存库,OkHttpUtils的使用,二次封装PicassoUtils实现微信精选 官网: http://square.github.i ...

  4. 深入理解MVC C#+HtmlAgilityPack+Dapper走一波爬虫 StackExchange.Redis 二次封装 C# WPF 用MediaElement控件实现视频循环播放 net 异步与同步

    深入理解MVC   MVC无人不知,可很多程序员对MVC的概念的理解似乎有误,换言之他们一直在错用MVC,尽管即使如此软件也能被写出来,然而软件内部代码的组织方式却是不科学的,这会影响到软件的可维护性 ...

  5. Java 面向对象(二)封装

    一.封装(Encapsulation) 1.概述 封装是面向对象编程的核心思想.把对象的属性和行为封装起来,其载体就是类. 面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的, ...

  6. 二次封装这几个 element-ui 组件后,大大减少了我 CRUD 的时间

    element-ui 因其组件丰富.可拓展性强.文档详细等优点成为 Vue 最火的第三方 UI 框架.element-ui 其本身就针对后台系统设计了很多实用的组件,基本上满足了平时的开发需求. 既然 ...

  7. 《手把手教你》系列基础篇(九十七)-java+ selenium自动化测试-框架设计篇-Selenium方法的二次封装和页面基类(详解教程)

    1.简介 上一篇宏哥介绍了如何设计支持不同浏览器测试,宏哥的方法就是通过来切换配置文件设置的浏览器名称的值,来确定启动什么浏览器进行脚本测试.宏哥将这个叫做浏览器引擎类.这个类负责获取浏览器类型和启动 ...

  8. 对百度WebUploader开源上传控件的二次封装,精简前端代码(两句代码搞定上传)

    前言 首先声明一下,我这个是对WebUploader开源上传控件的二次封装,底层还是WebUploader实现的,只是为了更简洁的使用他而已. 下面先介绍一下WebUploader 简介: WebUp ...

  9. iOS项目相关@AFN&SDWeb的二次封装

    一,AFNetworking跟SDWebImge是功能强大且常用的第三方,然而在实际应用中需要封装用来复用今天就跟大家分享一下AFN&SDWeb的二次封装 1. HttpClient.h及.m ...

随机推荐

  1. Android自定义控件总结

    自定义控件分类: 1.使用系统控件,实现自定义的效果 2.自己定义一个类继承View ,如textView.ImageView等,通过重写相关的方法来实现新的效果 3.自己定义一个类继承ViewGro ...

  2. Python学习笔记【第十四篇】:Python网络编程二黏包问题、socketserver、验证合法性

    TCP/IP网络通讯粘包问题 案例:模拟执行shell命令,服务器返回相应的类容.发送指令的客户端容错率暂无考虑,按照正确的指令发送即可. 服务端代码 # -*- coding: utf- -*- # ...

  3. 用CSS解决一个让人头疼的问题

    需求:下面的文字内容分别都写在一个a标签里,现在需要获取到每一行最后一个a标签的竖线,并删除  我首先想到的是用CSS3新增选择器—— :nth-child()来解决,比如 :nth-child(3n ...

  4. jQuery之animate()用法

    最近在学习jQuery,看到一个很有意思的函数animate(),但是在网上却没有查到相关的详细资料,于是打算参考jQuery API,自己总结一下. 概述 animate() 方法执行 CSS 属性 ...

  5. Google Chrome 书签导出并生成 MHTML 文件

    目的 因为某些原因需要将存放在 Google Chrome 内的书签导出到本地,所幸 Google Chrome 提供了导出书签的功能. 分析 首先在 Google Chrome 浏览器当中输入 ch ...

  6. 课程五(Sequence Models),第三周(Sequence models & Attention mechanism) —— 0.Practice questions:Sequence models & Attention mechanism

  7. Linux(CentOS)下安装Elasticsearch5.0.0

    一.ES5.0解压安装到Windows之后(可能)需要进行的设置: 1.如果不设置,直接运行elasticsearch.bat 文件 ,会报错: 2.解决方式 调节 conf/jvm.options ...

  8. [译]ASP.NET Core中使用MediatR实现命令和中介者模式

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9866068.html 在本文中,我将解释命令模式,以及如何利用基于命令模式的第三方库来实现它们,以及如何 ...

  9. Android--使用剪切板在Activity中传值

    在Activity之间传递数据还可以利用一些技巧,不管windows还是Linux操作系统,都会支持一种叫剪切板的技术,也就是某一个程序将一些数据复制到剪切板上,然后其他的任何程序都可以从剪切板中获取 ...

  10. 垂直居中—3行CSS3代码

    方法一: .element { position: relative; top: 50%; transform: translateY(-50%); } 这用用的好处了,无论是块级元素还是行内元素,都 ...