关于Fresco
fresco官网:
http://www.fresco-cn.org/
fresco先包括两个大板块:Image Pipeline和Drawees.
Fresco 是一个强大的图片加载组件。 Fresco 中设计有一个叫做*image pipeline*的模块。它负责从网络,从本地文件系统,本地资源加载图片。为了最大限度节省空间和CPU时间,它含有3级缓存设计(2级内存,1级文件)。 Fresco 中设计有一个叫做*Drawees*模块,方便地显示loading图,当图片不再显示在屏幕上时,及时地释放内存和空间占用。 Fresco 支持 Android2.3(API level 9) 及其以上系统。
环境搭建
compile 'com.facebook.fresco:fresco:1.3.0'// 支持webpcompile 'com.facebook.fresco:webpsupport:1.3.0'// gif加载使用compile 'com.facebook.fresco:animated-gif:1.3.0'// WebP(静态图+动图)加载使用compile 'com.facebook.fresco:animated-webp:1.3.0'
基本概念
我们先简单了解下fresco中的重要类
DraweeView:继承自View,一般情况下我们使用SimpleDraweeView类进行图片加载。关于其自定义属性稍后我们介绍
DraweeHierarchy:渲染图片内容的类,我们可以通过它在java代码里设置DraweeView的属性
DraweeController:负责框架底层的图片加载的类
Image Pipeline:(图形管道)完成图片的获取。不管是通过网络、本地文件、content provider还是本地资源,它都把图片压缩并缓存到磁盘,并且把内存作为第二缓存存储着解码后的图片
特性介绍
1. Image Pipeline
Fresco 中设计有一个叫做 Image Pipeline 的模块。它负责从网络,从本地文件系统,本地资源加载图片。为了最大限度节省空间和CPU时间,它含有3级缓存设计(2级内存,1级磁盘)。
2. Drawees
Fresco 中设计有一个叫做 Drawees 模块,它会在图片加载完成前显示占位图,加载成功后自动替换为目标图片。当图片不再显示在屏幕上时,它会及时地释放内存和空间占用。
3. 内存管理
解压后的图片,即Android中的Bitmap,占用大量的内存。大的内存占用势必引发更加频繁的GC。在5.0以下,GC将会显著地引发界面卡顿。
在5.0以下系统,Fresco将图片放到一个特别的内存区域。当然,在图片不显示的时候,占用的内存会自动被释放。这会使得APP更加流畅,减少因图片内存占用而引发的OOM。
4. 图片加载
Fresco的Image Pipeline允许你用很多种方式来自定义图片加载过程,比如:
- 为同一个图片指定不同的远程路径,或者使用已经存在本地缓存中的图片
- 先显示一个低清晰度的图片,等高清图下载完之后再显示高清图
- 加载完成回调通知
- 对于本地图,如有EXIF缩略图,在大图加载完成之前,可先显示缩略图
- 缩放或者旋转图片
- 对已下载的图片再次处理
5. 图片绘制
Fresco 的 Drawees 设计,带来一些有用的特性:
- 自定义居中焦点
- 圆角图,当然圆圈也行
- 下载失败之后,点击重现下载
- 自定义占位图,自定义overlay, 或者进度条
- 指定用户按压时的overlay
6. 图片的渐进式呈现
渐进式的JPEG图片格式已经流行数年了,渐进式图片格式先呈现大致的图片轮廓,然后随着图片下载的继续,呈现逐渐清晰的图片,这对于移动设备,尤其是慢网络有极大的利好,可带来更好的用户体验。
Android 本身的图片库不支持此格式,但是Fresco支持。使用时,和往常一样,仅仅需要提供一个图片的URI即可,剩下的事情,Fresco会处理。
7. Gif和Webp格式图片的强大支持
- 加载Gif图和WebP动图在任何一个Android开发者眼里看来都是一件非常头疼的事情。每一帧都是一张很大的Bitmap,每一个动画都有很多帧。Fresco让你没有这些烦恼,它处理好每一帧并管理好你的内存。
- 支持WebP解码,即使在早先对WebP支持不完善的Android系统上也能正常使用!
在XML中进行属性配置
Fresco有如下几种图层
/* 占位图层,即默认情况下显示的图层 */private final int mPlaceholderImageIndex;/* 进度条图层,即加载过程中的圆形或者线性进度条 */private final int mProgressBarImageIndex;/* 目标显示图层,即加载完成之后显示的图层 */private final int mActualImageIndex;/* 重试图层,即加载失败重试时显示的图层 */private final int mRetryImageIndex;/* 失败图层,即加载失败时显示的图层 */private final int mFailureImageIndex;/* 控制覆盖图层,即遮挡在最上方的图层 */private final int mControllerOverlayIndex;
围绕着这6个图层,我们的SimpleDraweeView布局一般包含如下主要元素
<com.facebook.drawee.view.SimpleDraweeView xmlns:fresco="http://schemas.android.com/apk/res-auto" android:id="@+id/image_fresco2" android:layout_width="100dip" android:layout_height="wrap_content" 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:roundedCornerRadius="5dip" fresco:roundTopLeft="true" fresco:roundTopRight="true" fresco:roundBottomLeft="true" fresco:roundBottomRight="true" fresco:roundWithOverlayColor="@color/colorAccent" fresco:roundingBorderWidth="2dip" fresco:roundingBorderColor="@color/colorPrimary" fresco:viewAspectRatio="1"/>
这里我就说一下scaleType。与ImageView相比,GenericDraweeView多了一个focusCrop这个属性。这个属性与centerCrop的区别在于前者可以自由定义聚焦点而后者的聚焦点是固定的。DraweeView显示时会尽量以此聚焦点为中心。 聚焦点是以相对坐标形式展现的,比如 (0f, 0f) 是左上角对齐显示,(1f, 1f) 是右下角对齐。这就使得聚焦点位置和具体尺寸无关,这是非常实用的。 如果将聚焦点设置为(0.5f, 0.5f) ,那么它和centerCrop是等价的。
如果要使用此缩放模式,首先在 XML 中指定缩放模式:
fresco:actualImageScaleType="focusCrop"
然后在Java代码中,给你的图片指定聚焦点:
hierarchy.setActualImageFocusPoint(PointF(
1
f,
1
f))
这里有几个注意的地方需要提醒一下大家
- SimpleDraweeView的宽高不能同时为wrap_content,需要使用match_parent或者一个固定值。除非你使用viewAspectRatio设置比例,在这种条件下宽、高中的其中一方可以是wrap_content
- 使用SimpleDraweeView的时候,facebook官方建议不要再使用ImageView的任何属性,如setImageResource、setBackground、setScaleType等这些ImageView中有但是View中没有的属性
进度条的制作
进度条目前有3种样式选择
系统默认的线性进度条
hierarchy.setProgressBarImage(ProgressBarDrawable())
任意一张图片,使用旋转动画
<?xml version="1.0" encoding="utf-8"?><animated-rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/load_progress_8" android:pivotX="50%" android:pivotY="50%"></animated-rotate>
直接使用该xml
渐进式图片加载
渐进式图片是从模糊到清楚的一种加载模式。fresco仅支持文件类型为JPEG的网络图片,因为本地图片均一次性解码完成,所以本地图片不需要使用渐进式。在fresco中,你可以设置一个清晰度标准,使其在达到这个标准之前一直以占位图显示。
支持图片类型
重试机制
DraweeController controller = Fresco.
newDraweeControllerBuilder
()
.setUri(uri)
.setOldController(
simpleDraweeView
.getController())
.setTapToRetryEnabled(
true
).build();
simpleDraweeView
.setController(controller);
代码实现:
simpleDraweeView
= findViewById(R.id.
iv
);
RoundingParams roundingParams =
new
RoundingParams();
roundingParams.setRoundAsCircle(
true
);
GenericDraweeHierarchy
hierarchy
= GenericDraweeHierarchyBuilder.
newInstance
(getResources())
.setRoundingParams(roundingParams)
.setFadeDuration(
5000
)
.build();
simpleDraweeView
.setHierarchy(
hierarchy
);
Picasso,Glide,Fresco的区别
- Picasso :和Square的网络库一起能发挥最大作用,因为Picasso可以选择将网络请求的缓存部分交给了okhttp实现。使用4.0+系统上的HTTP缓存来代替磁盘缓存.
Picasso 底层是使用OkHttp去下载图片,所以Picasso底层网络协议为Http.
- Glide:模仿了Picasso的API,而且在它的基础上加了很多的扩展(比如gif等支持),Glide默认的Bitmap格式是RGB_565,比Picasso默认的ARGB_8888格式的内存开销要小一半;Picasso缓存的是全尺寸的(只缓存一种),而Glide缓存的是跟ImageView尺寸相同的(即5656和128128是两个缓存) 。
Glide 底层默认使用的是HttpUrlConnection的方式请求网络,所以Glide的底层网络协议也为Http.
Fresco:最大的优势在于5.0以下(最低2.3)的bitmap加载。在5.0以下系统,Fresco将图片放到一个特别的内存区域(Ashmem区,这个区域没有被统计到App的内存使用里)。当然,在图片不显示的时候,占用的内存会自动被释放。这会使得APP更加流畅,减少因图片内存占用而引发的OOM。为什么说是5.0以下,因为在5.0以后系统默认就是存储在Ashmem区了。
Image pipeline 默认使用HttpURLConnection。应用可以根据自己需求使用不同的网络库。Fresco的Image Pipeline负责图片的获取和管理。图片可以来自远程服务器,本地文件,或者Content Provider,本地资源。压缩后的文件缓存在本地存储中,Bitmap数据缓存在内存中.
功能性 Fresco > Glide > Picasso
包大小 Fresco > Glide > Picasso
主要功能:
共有的功能:根据content生命周期进行图片加载或暂停和恢复,缓存图片到本地。
加载图片格式及大小:
- Picasso:下载全尺寸图片,load全尺寸图片到imageview上,图片使用ARGB-8888格式。
- Glide:包含Picasso功能,默认下载不同图片至本地,load 对应imageview尺寸的图片,图片使用ARGB-565格式。
可加载gif、缩略图、视频静态图片、转换字节数组、显示动画。
- Fresco:结合Picasso、Glide优点,更适用于加载大量图片。另支持渐进式显示图片、WebP格式图片。
对图片转换
- Picasso: picasso-transformations,:结合picasso,支持将图片转换为其他形状后显示。
- Glide: glide-transformations:结合glide,支持将图片转换为其他形状后显示。
- Fresco: android-gpuimage:支持将图片变幻为各种滤镜效果。
总结:
- Picasso所能实现的功能,Glide都能做,无非是所需的设置不同。但是Picasso体积比起Glide小太多,如果项目中网络请求本身用的就是okhttp或者retrofit(本质还是okhttp),那么建议用Picasso,体积会小很多(Square全家桶的干活)。
- Glide的好处是大型的图片流,比如gif、Video,如果你们是做美拍、爱拍这种视频类应用,建议使用。
- Fresco在5.0以下的内存优化非常好,代价就是体积也非常的大,按体积算Fresco>Glide>Picasso不过在使用起来也有些不便(小建议:它只能用内置的一个ImageView来实现这些功能,用起来比较麻烦,我们通常是根据Fresco自己改改,直接使用他的Bitmap层).
加载最先可用的图片
大部分时候,一张图片只有一个 URI。加载它,然后工作完成~
但是假设同一张图片有多个 URI 的情况。比如,你可能上传过一张拍摄的照片。原始图片太大而不能上传,所以图片首先经过了压缩。在这种情况下,首先尝试获取本地压缩后的图片 URI,如果失败的话,尝试获取本地原始图片 URI,如果还是失败的话,尝试获取上传到网络的图片 URI。直接下载我们本地可能已经有了的图片不是一件光彩的事。
Image pipeline 会首先从内存中搜寻图片,然后是磁盘缓存,再然后是网络或其他来源。对于多张图片,不是一张一张按上面的过程去做,而是 pipeline 先检查所有图片是否在内存。只有没在内存被搜寻到的才会寻找磁盘缓存。还没有被搜寻到的,才会进行一个外部请求。
使用时,创建一个image request 数组,然后传给
ControllerBuilder
:
Uri uri1, uri2;ImageRequest request = ImageRequest.fromUri(uri1);ImageRequest request2 = ImageRequest.fromUri(uri2);ImageRequest[] requests = { request1, request2 };DraweeController controller = Fresco.newDraweeControllerBuilder() .setFirstAvailableImageRequests(requests) .setOldController(mSimpleDraweeView.getController()) .build();mSimpleDraweeView.setController(controller);
先显示低分辨率的图,然后是高分辨率的图
假设你要显示一张高分辨率的图,但是这张图下载比较耗时。与其一直显示占位图,你可能想要先下载一个较小的缩略图。
这时,你可以设置两个图片的URI,一个是低分辨率的缩略图,一个是高分辨率的图。
Uri lowResUri, highResUri;DraweeController controller = Fresco.newDraweeControllerBuilder() .setLowResImageRequest(ImageRequest.fromUri(lowResUri)) .setImageRequest(ImageRequest.fromUri(highResUri)) .setOldController(mSimpleDraweeView.getController()) .build();mSimpleDraweeView.setController(controller);
注意:动图无法在低分辨率显示
该如何选择图片加载库?
如果你手中的项目比较老旧,而且代码量较大,你又没什么时间去大改,那么继续维持当前的选择是比较稳妥的办法。如果是新上马的项目,那么UIL由于不再维护、Picasso基本被Glide全方位超越,我推荐使用Glide或Fresco。如果你的App里,图片特别多,而且都是很大、质量很高的图 片,而且你不太在乎App的体积(可能性不大),那么Fresco就是很好的选择了,而Glide相比较Fresco,Glide要轻量一些,而且是Google官方推荐,所以在多数时候,会是开发者的首选。话说回来,如果你对这些图库都不满意,那可以自己写一个,如果可以的话!!