转载请注明转自http://write.blog.csdn.net/postedit/50459154【小曾的博客】
Fresco 是一个强大的图片加载组件。
Fresco 中设计有一个叫做 image pipeline 的模块。它负责从网络,从本地文件系统,本地资源加载图片。为了最大限度节省空间和CPU时间,它含有3级缓存设计(2级内存,1级文件)。
Fresco 中设计有一个叫做 Drawees 模块,方便地显示loading图,当图片不再显示在屏幕上时,及时地释放内存和空间占用。
Fresco 支持 Android2.3(API level 9) 及其以上系统。
MVC模式
现在听好多人都在谈设计模式一些MVC和MVP等设计模式,然后DraweeView也是MVC模式的。
DraweeView
类(实际上是DraweeHolder
),其负责展示数据,显示图片。DraweeHierarchy
类,其负责持有数据,用一个层级组织和维护最终绘制和显示的图片。DraweeController
类,其负责控制数据的逻辑。文字略显苍白,图片才是最好的诠释方式,其中代码是示意使用后续会分析到。如图:
在Fresco的框架中,DraweeView
背后的DraweeHolder
持有了DraweeHierarchy
和DraweeController
两个类的引用。SimpleDraweeView
使用setImageUri()
方法发出要显示图片的请求。
随后,通过一系列的操作去构造DraweeController
的实例以便发出请求和更新视图。然后,马上使用setController()
方法以及setHierarchy()
方法,通知DraweeView
视图的改变以显示加载效果(此时还是图片请求过程中)。
最后,通过DraweeController
请求成功的回调,再次通知DraweeHierarchy
视图改变,以完成显示图片的全部操作。
其实文档说的很清楚了怎么使用Fresco,但是要学习就得自己去实践
$gitclone https://github.com/facebook/fresco.git
2.第二步添加Fresco到项目工程:
不解释直接加到build.gradle里面:
compile'com.facebook.fresco:fresco:0.7.0+'
然后就是一段时间的下载,也是够了
官方文档已经说fresco的类库发布到了Maven中央库,所以我们只需添加上面的代码配置再同步编译即可
repositories { jcenter() mavenCentral() }下面我们就来实践使用咯。既然要看网络加载图片,那我们必须在清单文件里面加网络访问权限
现在我们来使用一下SimpleDraweeView
XML属性 | 意义 |
---|---|
fadeDuration | 淡入淡出动画持续时间(单位:毫秒ms) |
actualImageScaleType | 实际图像的缩放类型 |
placeholderImage | 占位图 |
placeholderImageScaleType | 占位图的缩放类型 |
progressBarImage | 进度图 |
progressBarImageScaleType | 进度图的缩放类型 |
progressBarAutoRotateInterval | 进度图自动旋转间隔时间(单位:毫秒ms) |
failureImage | 失败图 |
failureImageScaleType | 失败图的缩放类型 |
retryImage | 重试图 |
retryImageScaleType | 重试图的缩放类型 |
backgroundImage | 背景图 |
overlayImage | 叠加图 |
pressedStateOverlayImage | 按压状态下所显示的叠加图 |
roundAsCircle | 设置为圆形图 |
roundedCornerRadius | 圆角半径 |
roundTopLeft | 左上角是否为圆角 |
roundTopRight | 右上角是否为圆角 |
roundBottomLeft | 左下角是否为圆角 |
roundBottomRight | 右下角是否为圆角 |
roundingBorderWidth | 圆形或者圆角图边框的宽度 |
roundingBorderColor | 圆形或者圆角图边框的颜色 |
roundWithOverlayColor | 圆形或者圆角图底下的叠加颜色(只能设置颜色) |
viewAspectRatio | 控件纵横比 |
先使用本地占位图片:placeholderImage设置圆圈:roundAsCircle 设置圆弧角度:roundedCornerRadius
麻麻再也不用担心我写不出圆形图片了
<com.facebook.drawee.view.SimpleDraweeView android:id="@+id/icon1" android:layout_width="50dp" android:layout_height="50dp" fresco:roundAsCircle="true" fresco:roundedCornerRadius="180dp" fresco:actualImageScaleType="focusCrop" fresco:placeholderImage="@mipmap/alipay" fresco:placeholderImageScaleType="fitCenter" />
大家可能看到,属性中存在fresco:开头的声明。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:fresco="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" >
这个是fresco的自定义属性,如果我们需要使用其自定义属性,必须在我们的xml根布局中添加声明/命名空间,上图蓝色部分
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Fresco.initialize(this); setContentView(R.layout.activity_main); }切记 Fresco.initialize(this);必须放在设置布局的前面,而且不写还不行,不要问我为什么,哥也不知道。
看效果图:
圆形图片就是这样轻松的出来了,感觉心里有点小激动。
然后我们来个圆角图片:
<com.facebook.drawee.view.SimpleDraweeView android:layout_marginLeft="100dp" android:layout_width="50dp" android:layout_height="50dp" fresco:roundAsCircle="false" fresco:roundedCornerRadius="5dp" fresco:actualImageScaleType="focusCrop" fresco:placeholderImage="@mipmap/alipay" fresco:placeholderImageScaleType="fitCenter" android:layout_centerVertical="true" />
接下来我们代码来实现圆角图片:
创建时设置
RoundingParams roundingParams = new RoundingParams();
roundingParams.setCornersRadius(mContext.getResources().getDimensionPixelOffset(R.dimen.sound_category_item_radius));
GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(mContext.getResources());
GenericDraweeHierarchy hierarchy = builder.build();
hierarchy.setRoundingParams(roundingParams);
mCategoryCoverIv.setHierarchy(hierarchy);
运行时修改
RoundingParams roundingParams = simpleDraweeView.getHierarchy().getRoundingParams(); roundingParams.setBorder(R.color.red, 1.0); roundingParams.setRoundAsCircle(true); simpleDraweeView.getHierarchy().setRoundingParams(roundingParams);
1、设置圆角时,支持4个角不同的半径。XML中无法配置,但可在Java代码中配置。 四个角不同半径实现
RoundingParams roundingParams = new RoundingParams();
roundingParams.setCornersRadii(10, 20, 30, 40);
GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(mContext.getResources());
GenericDraweeHierarchy hierarchy = builder.build();
hierarchy.setRoundingParams(roundingParams);
viewHolder.mCategoryCoverIv.setHierarchy(hierarchy);
然而用xml却不能实现,醉了,xml 是通过叠加一个solid color来绘制圆角。但是背景需要固定成指定的颜色。 在XML中指定 roundWithOverlayColor, 或者通过调用setOverlayColor来完成此设定。
对于同一个View,请不要多次调用setHierarchy
,即使这个View是可回收的。创建 DraweeHierarchy 的较为耗时的一个过程,应该多次利用。
如果要改变所要显示的图片可使用setController
或者 setImageURI
。
接下来我们代码来实现加载网络图片:
先布局我们也不设置加载成功,加载失败图片和占位图:
<com.facebook.drawee.view.SimpleDraweeView android:id="@+id/icon1" android:layout_width="200dp" android:layout_height="200dp" android:layout_centerInParent="true" fresco:actualImageScaleType="focusCrop" />然后 在代码中具体的使用:
private void initView() { //创建SimpleDraweeView对象 simpleDraweeView = (SimpleDraweeView) findViewById(R.id.icon1); //创建将要下载的图片的URI Uri imageUri = Uri.parse("http://img.my.csdn.net/uploads/201407/26/1406383243_5120.jpg"); //开始下载 simpleDraweeView.setImageURI(imageUri); }神奇的事情出现了:
由于没有设置加载过程的图片,所以感觉不是很友好,像是等了很久,最后还是出现图片了(还以为不行呢)
然后我们还可以改变图片的大小,避免内存溢出:
/** * 显示缩略图(把原始图片变小) */ public void showThumb(){ //创建SimpleDraweeView对象 simpleDraweeView = (SimpleDraweeView) findViewById(R.id.icon1); //创建将要下载的图片的URI Uri imageUri = Uri.parse("http://img.my.csdn.net/uploads/201407/26/1406383243_5120.jpg"); ImageRequest request = ImageRequestBuilder.newBuilderWithSource(imageUri) .setResizeOptions(new ResizeOptions(dip2px(this, 80), dip2px(this, 80))) .build(); DraweeController controller = Fresco.newDraweeControllerBuilder() .setImageRequest(request) .setOldController(simpleDraweeView.getController()) .setControllerListener(new BaseControllerListener<ImageInfo>()) .build(); simpleDraweeView.setController(controller); } /** * dp 转像素 * @param context * @param dpValue * @return */ private int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; int value=(int) (dpValue * scale + 0.5f); return value; }这里还要特别注意的是:出问题了 看官方文档 Resizing
此方法 只支持JPG, 只支持JPG, 只支持JPG, 草,
ImagePipelineConfig config = ImagePipelineConfig.newBuilder(this)
.setDownsampleEnabled(true)
.build();
Fresco.initialize(this, config);
在初始化的时候这样写就可以支持Png什么的了。
如果你懒, 那么,当你出现问题,有几个地方你得去瞅瞅咯:
Fresco Issue 567 这里有一些PNG图片展示的TooManyBitmapsException,是不是感觉github就是程序员的天堂,牛逼可不可以这样吹
自动旋转
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri).setAutoRotateEnabled
(true).build();
好了那些什么网络加载过程中的加载成功失败图片的效果就不演示了。
对于 Drawee 的各种效果配置,其中一些是支持缩放类型的。
类型 | 描述 |
---|---|
center | 居中,无缩放。 |
centerCrop | 保持宽高比缩小或放大,使得两边都大于或等于显示边界,且宽或高契合显示边界。居中显示。 |
focusCrop | 同centerCrop, 但居中点不是中点,而是指定的某个点。 |
centerInside | 缩放图片使两边都在显示边界内,居中显示。和 fitCenter 不同,不会对图片进行放大。如果图尺寸大于显示边界,则保持长宽比缩小图片。 |
fitCenter | 保持宽高比,缩小或者放大,使得图片完全显示在显示边界内,且宽或高契合显示边界。居中显示。 |
fitStart | 同上。但不居中,和显示边界左上对齐。 |
fitEnd | 同fitCenter, 但不居中,和显示边界右下对齐。 |
fitXY | 不保存宽高比,填充满显示边界。 |
none | 如要使用tile mode显示, 需要设置为none |
这些缩放类型和Android ImageView 支持的缩放类型几乎一样.
唯一不支持的缩放类型是 matrix
。Fresco 提供了 focusCrop
作为补充,通常这个使用效果更佳。
实际图片,占位图,重试图和失败图都可以在 xml 中进行设置,用fresco:actualImageScaleType
这样的属性。你也可以使用 GenericDraweeHierarchyBuilder
类在代码中进行设置。 即使显示效果已经构建完成,实际图片的缩放类型仍然可以通过GenericDraweeHierarchy
类在运行中进行修改。 不要使用 android:scaleType
属性,也不要使用setScaleType()
方法,它们对 Drawees 无效。
centerCrop
缩放模式会保持长宽比,放大或缩小图片,填充满显示边界,居中显示。这个缩放模式在通常情况下很有用。
但是对于人脸等图片时,一味地居中显示,这个模式可能会裁剪掉一些有用的信息。
以人脸图片为例,借助一些类库,我们可以识别出人脸所在位置。如果可以设置以人脸位置居中裁剪显示,那么效果会好很多。
Fresco的focusCrop缩放模式正是为此而设计。只要提供一个居中聚焦点,显示时就会尽量以此点为中心。
居中点是以相对方式给出的,比如 (0f, 0f) 是左上对齐显示,(1f, 1f) 是右下角对齐。相对坐标使得居中点位置和具体尺寸无关,这是非常实用的。
(0.5f, 0.5f) 的居中点位置和缩放类型 centerCrop
是等价的。
如果要使用此缩放模式,首先在 XML 中指定缩放模式:
fresco:actualImageScaleType="focusCrop"
在Java代码中,给你的图片指定居中点:
PointF focusPoint;
// your app populates the focus point
mSimpleDraweeView
.getHierarchy()
.setActualImageFocusPoint(focusPoint);
如果你要使用tile mode进行显示,那么需要将scale type 设置为none.
更多的效果和属性请自行去看:http://fresco-cn.org/docs/getting-started.html(里面有详细的介绍,个人感觉很不错的中文文档,麻麻再也不需要担心我的英语了)你也可以去看下http://blog.csdn.net/y1scp/article/details/49245535,里面或许有你想要的效果额,累了睡觉了,这东西也是看到了,听说性能是相当的不错:
这里我们采用Picasso来与Fresco进行比较。(这里参考http://www.jianshu.com/p/d0b001bfa1a4)
上下滑动列表,观察应用的Java Heap和Native Heap的大小
Picasso
Fresco
可以看到,使用Picasso的,其Java heap高达38M。而Fresco则将其控制在了10M以内。极大的减小了OOM的风险。
不过Native Heap占用很吓人,80MB。
那么使用ADB去查看一下内存:
Picasso时的内存
Fresco时的内存
可以看到Fresco的Native Heap大小的确是70M,不过只占用了15M左右。而Fresco的Dalvik Heap占用为不到9M,是Picasso的四分之一还少,总共内存占用只有24M,是Picasso的一半左右。
实在要睡觉了,写个博客真的好累,有什么好的对Fresco的详解可以回复我,让我也多去学习一下,没有时间去看源码,那就学习别人的东西咯。