Android四大图片缓存框架之-Fresco(一)
最后更新于:2022-04-01 15:48:55
本文来自于[Fresco中文文档](http://www.fresco-cn.org/),这仅仅是自己的学习笔记!!!大牛绕路,放我我。
关于Fresco的介绍,请查看[链接](http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0402/2683.html)
关于android图片缓存,这是一个android程序员必须了解的。关于四大图片缓存框架的特性与对比,请移步MDCC[传送门](http://www.csdn.net/article/2015-10-21/2825984)
首先说明,本文的大多数内容来自于官方文档,请勿喷!!!
那么今天我们就来了解下Fresco,作为FB出版的开源项目,据说是目前最好的缓存框架。
那么我们就先来了解下Fresco是个什么。
- Fresco是一个强大的图片加载组件
- Fresco中设计有一个叫做image pipeline 的模块。他负责从网络,从本地文件系统,本地资源加载图片。为了最大限度上节省空间和CPU时间,它含有3级缓存的设计(额,没三级能拿出手?)
- Fresco中设计有一个叫做Drawees模块,方便地显示loading图,当图片不再显示在屏幕上时,及时地释放内存和空间占用。
- Fresco支持Android2.3及以上系统
简单的看下使用SimpleDraweeView显示一张占位图。在XML文件中加入
~~~
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true"
>
</com.facebook.drawee.view.SimpleDraweeView>
~~~
在代码中设置Uri,
~~~
draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);
Uri uri = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/fresco-logo.png");
// draweeView.setController(draweeController);
draweeView.setImageURI(uri);
~~~
最后添加网络权限,就可以了。我们在来看下这里的Uri支持什么格式:
- 远程图片 http:// 或者 https://
- 本地文件 file://
- Content Provider content://
- asset目录下的资源 asset://
- res目录下的资源 res://包名/+R……
接下来便详细的介绍Drawee
举个栗子:
~~~
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="20dp"
android:layout_height="20dp"
fresco:fadeDuration="300"
fresco:actualImageScaleType="focusCrop"
fresco:placeholderImage="@color/wait_color"
fresco:placeholderImageScaleType="fitCenter"
fresco:failureImage="@drawable/error"
fresco:failureImageScaleType="centerInside"
fresco:retryImage="@drawable/retrying"
fresco:retryImageScaleType="centerCrop"
fresco:progressBarImage="@drawable/progress_bar"
fresco:progressBarImageScaleType="centerInside"
fresco:progressBarAutoRotateInterval="1000"
fresco:backgroundImage="@color/blue"
fresco:overlayImage="@drawable/watermark"
fresco:pressedStateOverlayImage="@color/red"
fresco:roundAsCircle="false"
fresco:roundedCornerRadius="1dp"
fresco:roundTopLeft="true"
fresco:roundTopRight="false"
fresco:roundBottomLeft="false"
fresco:roundBottomRight="true"
fresco:roundWithOverlayColor="@color/corner_color"
fresco:roundingBorderWidth="2dp"
fresco:roundingBorderColor="@color/border_color"
/>
~~~
上面这个是官方的栗子,上面有所有的属性,我们就来看看,这些属性代表什么意思,
- layout_width和layout_height 不支持warp_content,但是可以通过setAspectRetio();来设置宽高比
- fadeDuration() 淡..时间
- actualImageScaleType 设置图片缩放,通常使用foucsCrop,该属性值会通过算法把人头像放在中间,关于缩放,请移步[黑洞](http://www.fresco-cn.org/docs/scaling.html#_)
- placeholderImage 下载成功之前显示的图片
- placeholderImageScaleType
- failureImage 加载失败时显示的图片
- failureImageScaleType
- retryImage 加载失败,提示用户点击重新加载的图片
- retryImageScaleType
- progressBarImage 提示 用户正在加载,和进度无关
- progressBarImageScaleType
- progressBarAutoRotateInterval 图片自动旋转的时间间隔
- backgroundImage 背景
- overlayImage 叠加图
- pressedStateOverlayImage 按下时候的叠加图
- roundAsCircle 是否涉及圆圈
- roundedCornerRadius 圆角
- roundTopLeft、roundTopRight….. 分别设置4个角不同半径,设置为true以后可以再代码中设置角度。通过RoundingParams的setConnersRadii()方法
~~~
public RoundingParams setCornersRadii(float topLeft, float topRight, float bottomRight, float bottomLeft) {
float[] radii = this.getOrCreateRoundedCornersRadii();
radii[0] = radii[1] = topLeft;
radii[2] = radii[3] = topRight;
radii[4] = radii[5] = bottomRight;
radii[6] = radii[7] = bottomLeft;
return this;
}
~~~
- roundWithOverlayColor,边框的叠加颜色
- roundingBorderWidth 边框宽度
-
roundingBorderColor 边框颜色
我们看到,仅仅靠xml文件的属性,功能就已经很强大了。我们通过什么来在代码中设置各种效果呢?看代码
~~~
GenericDraweeHierarchyBuilder builder =
new GenericDraweeHierarchyBuilder(getResources());
GenericDraweeHierarchy hierarchy = builder
.setFadeDuration(300)
.setPlaceholderImage(new MyCustomDrawable())
.setBackgrounds(backgroundList)
.setOverlays(overlaysList)
.build();
mSimpleDraweeView.setHierarchy(hierarchy);
~~~
DraweeHierarchy的一些属性可以在运行时改变。
~~~
GenericDraweeHierarchy hierarchy =mSimpleDraweeView.getHierarchy();
hierarchy.setPlaceholderImage(R.drawable.placeholderId);
~~~
注意:对于同一个View,不要多次调用setHierarchy。
我们看看GenericDraweeHierarchy提供了哪些set方法
![看这里看这里](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-08_57076805010fa.jpg "")
看到这里有相当多的drawable啊。我们在来看看,Fresco源码中有哪些Drawable,
![drawable](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-08_570768052009d.jpg "")
我们在set…(new ..Drawable),就可以轻松使用了。我们以ProgressBarDrawable为例,看看他提供了哪些方法。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-08_5707680538312.jpg "")
,看起来还是很强大的。当然,我们可以自定义Drawable,关于自定义Drawable,我这里就不再说了,网上还是很多的。
我们在来看看ControllerBuilder,从字面上就可以看出,这个可以对图片做出一些控制。
~~~
ControllerListener listener = new BaseControllerListener() {...}
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(uri)
.setTapToRetryEnabled(true)
.setOldController(mSimpleDraweeView.getController())
.setControllerListener(listener)
.build();
mSimpleDraweeView.setController(controller);
~~~
在指定一个新的controller的时候,使用setOldController,可以节省不必要的内存分配。
我们来看看Fresco.newDraweeControllerBuilder()有哪些set方法。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-08_5707680553c8f.jpg "")
自定义图片加载请求
~~~
Uri uri;
Postprocessor myPostprocessor = new Postprocessor() { ... }
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setPostprocessor(myPostprocessor)
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setOldController(mSimpleDraweeView.getController())
// 其他设置
.build();
~~~
渐进式JPEG图
~~~
ProgressiveJpegConfig pjpegConfig = new ProgressiveJpegConfig() {
@Override
public int getNextScanNumberToDecode(int scanNumber) {
return scanNumber + 2;
}
public QualityInfo getQualityInfo(int scanNumber) {
boolean isGoodEnough = (scanNumber >= 5);
return ImmutableQualityInfo.of(scanNumber, isGoodEnough, false);
}
}
ImagePipelineConfig config = ImagePipelineConfig.newBuilder()
.setProgressiveJpegConfig(pjpeg)
.build();
~~~
~~~
Uri uri;
ImageRequest request = ImageRequestBuilder
.newBuilderWithSource(uri)
.setProgressiveRenderingEnabled(true)
.build();
PipelineDraweeController controller = Fresco.newControllerBuilder()
.setImageRequest(requests)
.setOldController(mSimpleDraweeView.getController())
.build();
mSimpleDraweeView.setController(controller);
~~~
Gif动态图
~~~
Uri uri;
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
. // other setters
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setAutoPlayAnimations(true)
. // other setters
.build();
mSimpleDraweeView.setController(controller);
~~~
手动控制动态图播放
~~~
ControllerListener controllerListener = new BaseControllerListener<ImageInfo>() {
@Override
public void onFinalImageSet(
String id,
@Nullable ImageInfo imageInfo,
@Nullable Animatable anim) {
if (anim != null) {
// app-specific logic to enable animation starting
anim.start();
}
};
Uri uri;
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(uri)
.setControllerListener(controllerListener)
// other setters
.build();
mSimpleDraweeView.setController(controller);
~~~
使用动画
~~~
Animatable animation = mSimpleDraweeView.getController().getAnimatable();
if (animation != null) {
// 开始播放
animation.start();
// 一段时间之后,根据业务逻辑,停止播放
animation.stop();
}
~~~
多图请求以及图片复用
~~~
Uri lowResUri, highResUri;
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setLowResImageRequest(ImageRequest.fromUri(lowResUri))
.setImageRequest(ImageRequest.fromUri(highResUri))
.setOldController(mSimpleDraweeView.getController())
.build();
mSimpleDraweeView.setController(controller);
~~~
缩略图预览
~~~
Uri uri;
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setLocalThumbnailPreviewsEnabled(true)
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setOldController(mSimpleDraweeView.getController())
.build();
mSimpleDraweeView.setController(controller);
~~~
本地图片复用
~~~
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);
~~~
监听下载事件
~~~
ControllerListener controllerListener = new BaseControllerListener<ImageInfo>() {
@Override
public void onFinalImageSet(
String id,
@Nullable ImageInfo imageInfo,
@Nullable Animatable anim) {
if (imageInfo == null) {
return;
}
QualityInfo qualityInfo = imageInfo.getQualityInfo();
FLog.d("Final image received! " +
"Size %d x %d",
"Quality level %d, good enough: %s, full quality: %s",
imageInfo.getWidth(),
imageInfo.getHeight(),
qualityInfo.getQuality(),
qualityInfo.isOfGoodEnoughQuality(),
qualityInfo.isOfFullQuality());
}
@Override
public void onIntermediateImageSet(String id, @Nullable ImageInfo imageInfo) {
FLog.d("Intermediate image received");
}
@Override
public void onFailure(String id, Throwable throwable) {
FLog.e(getClass(), throwable, "Error loading %s", id)
}
};
Uri uri;
DraweeController controller = Fresco.newControllerBuilder()
.setControllerListener(controllerListener)
.setUri(uri);
// other setters
.build();
mSimpleDraweeView.setController(controller);
~~~
修改图片尺寸
~~~
Uri uri = "file:///mnt/sdcard/MyApp/myfile.jpg";
int width = 50, height = 50;
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setResizeOptions(new ResizeOptions(width, height))
.build();
PipelineDraweeController controller = Fresco.newDraweeControllerBuilder()
.setOldController(mDraweeView.getController())
.setImageRequest(request)
.build();
mSimpleDraweeView.setController(controller);
~~~
自动旋转
~~~
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setAutoRotateEnabled(true)
.build();
~~~
图片的修改。后处理器
~~~
Uri uri;
Postprocessor redMeshPostprocessor = new BasePostprocessor() {
@Override
public String getName() {
return "redMeshPostprocessor";
}
@Override
public void process(Bitmap bitmap) {
for (int x = 0; x < bitmap.getWidth(); x+=2) {
for (int y = 0; y < bitmap.getHeight(); y+=2) {
bitmap.setPixel(x, y, Color.RED);
}
}
}
}
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setPostprocessor(redMeshPostprocessor)
.build();
PipelineDraweeController controller = (PipelineDraweeController)
Fresco.newDraweeControllerBuilder()
.setImageRequest(request)
.setOldController(mSimpleDraweeView.getController())
// other setters as you need
.build();
mSimpleDraweeView.setController(controller);
~~~
图片请求 Image Requests
~~~
Uri uri;
ImageDecodeOptions decodeOptions = ImageDecodeOptions.newBuilder()
.setBackgroundColor(Color.GREEN)
.build();
ImageRequest request = ImageRequestBuilder
.newBuilderWithSource(uri)
.setAutoRotateEnabled(true)
.setLocalThumbnailPreviewsEnabled(true)
.setLowestPermittedRequestLevel(RequestLevel.FULL_FETCH)
.setProgressiveRenderingEnabled(false)
.setResizeOptions(new ResizeOptions(width, height))
.build();
~~~
上面我们说了Deawee,下面我们说下Image Pipeline
配置代码
~~~
ImagePipelineConfig config = ImagePipelineConfig.newBuilder()
.setBitmapMemoryCacheParamsSupplier(bitmapCacheParamsSupplier)
.setCacheKeyFactory(cacheKeyFactory)
.setEncodedMemoryCacheParamsSupplier(encodedCacheParamsSupplier)
.setExecutorSupplier(executorSupplier)
.setImageCacheStatsTracker(imageCacheStatsTracker)
.setMainDiskCacheConfig(mainDiskCacheConfig)
.setMemoryTrimmableRegistry(memoryTrimmableRegistry)
.setNetworkFetchProducer(networkFetchProducer)
.setPoolFactory(poolFactory)
.setProgressiveJpegConfig(progressiveJpegConfig)
.setRequestListeners(requestListeners)
.setSmallImageDiskCacheConfig(smallImageDiskCacheConfig)
.build();
Fresco.initialize(context, config);
~~~
是在是太多了,我也懒的写了。
参考资料:[中文文档](http://www.fresco-cn.org/)