Fresco简介
CSDN: tony_851122
- 一,概述
1,FaceBook开源的Android平台图片加载库,ReactNative的Android图片库
2,支持从网络,ContentProvider,本地存储,Asset,Resource数据源加载图片
3,两级内存缓存,Memory&Disk
4,支持JPEG,PNG,Progressive JPEG,Gif,WebP格式
- Support Android2.3 and later
- gitHub地址和文档地址
https://github.com/facebook/fresco
https://www.fresco-cn.org/docs
- 二,使用例子
2.1入口类
入口类是“Fresco”,单例模式。
2.1.1 初始化接口
initialize(Context context,
@Nullable ImagePipelineConfig imagePipelineConfig,
@Nullable DraweeConfig draweeConfig)
2.1.2 ImagePipelineConfig
a)缓存的参数,CacheKeyFactory
b)用什么netFetcher(okHttp)
c)是否支持webpng
d)定制imageDecoder
2.1.3 DraweeConfig
a)customDrawableFactories,定制显示的Drawable
b)PipelineDraweeControllerFactory,定制DraweeView的ControllerFactory
2.2 加载一个图片到ImageView例子
2.2.1 构建图层DraweeHierarchy
ImageView targetView;
GenericDraweeHierarchyBuilder genericDraweeHierarchyBuilder =
new GenericDraweeHierarchyBuilder(context.getResources()).
setPlaceholderImage(placeholderDrawable).
setActualImageScaleType(CenterCrop).
setBackgroun(backGroundDrawable).
setDesiredAspectRatio(4/3);
GenericDraweeHierarchy hierarchy = genericDraweeHierarchyBuilder.build();
targetView.setImageDrawable(mDraweeHolder.getTopLevelDrawable());
2.2.2 构建请求同时将其设置到controller中
Uri uri = Uri.parse(“http://www.fb.com/image”);
ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(uri).build;
PipelineDraweeControllerBuilder controllerBuilder = Fresco.newDraweeControllerBuilder()
.setImageRequest(imageRequest)
.setOldController(mDraweeHolder.getController());
DraweeController draweeController = controllerBuilder.build();
draweeController.setHierarchy(hierarchy);
2.2.3 根据生命周期时间,启动展示或停止展示
targetView.addOnAttachStateChangeListener(attachStateListener);
public void onAttachedToWindow(View v) {
draweeController.onAttach();
}
public void onDetachedToWindow(View v) {
draweeController.onDetach();
}
2.3 Fresco提供的SimpleDraweeView,封装了流程,更方便使用
在XML中直接使用:
<com.facebook.drawee.view.SimpleDraweeView
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"
/>
- 三,整体结构图 MVC
整体结构是一个类似MVC的结构。如下图所示,其中DraweeView是整个框架的容器,负责生命周期和Touch事件的控制。DraweeHierarchy充当View模块进行显示。ImagePipeline充当数据模块提供数据的获取。ImageRequest是请求,具体定制每次的要展示的请求参数。DraweeController是控制模块,接受请求,并管理从数据源获得数据将其最终显示在View上。
图3.1 整体结构图
3.1 DraweeView
1,继承于ImageView
2,只是个容器,不要使用原来的imageview的方法,不再有意义
3,GenericDraweeView
4,simpleDraweeView
5,DraweeHolder(Hierarchy,controller)
6,生命周期(onAttach,onDetach,onVisiblityChange,onDraw)
3.2 DraweeHierarchy
真正展示的图层,View中使用的是图层的最顶层Drawable。图层顾名思义是很多drawable组成,包括真正Image展示层,占位图层,失败展示图层,重试图层,加载进度图层。这些图层都隶属于一种FadeDrawable,这个FadeDrawable通过控制各个不同drawable层的alpha值,来控制不同层是否对用户可见,从而达到在不同状态下显示给用户想要的Drawable。
图3.2 simpleDraweeView的图层
3.3 PipelineDraweeController
在接收到onAttach的生命周期时,首先到BitmapCache内存缓存中查找请求的图片是否已经存在,如果存在则直接用找到的图片展示,并停止接下来的步骤。如果没有找到则调用其DataSourceGet接口利用Pipeline去发起一次图片的完整查找和生成流程,并设置结果的回调函数。当回调函数返回成功的结果Image,我们将其封装成要展示的Drawable,并将其设置到DrawableHierarchy中,从而真正显示给用户。
图3.2 Controller的工作流程
3.4 ImageRequest
ImageRequest主要用来设定请求的参数,主要设定的参数如下:
1) uri:请求目标地址
支持的URI类型:
1.1) int SOURCE_TYPE_NETWORK = 0;
1.2) int SOURCE_TYPE_LOCAL_FILE = 1;
1.3) int SOURCE_TYPE_LOCAL_VIDEO_FILE = 2;
1.4) int SOURCE_TYPE_LOCAL_IMAGE_FILE = 3;
1.5) int SOURCE_TYPE_LOCAL_CONTENT = 4;
1.6) int SOURCE_TYPE_LOCAL_ASSET = 5;
1.7) int SOURCE_TYPE_LOCAL_RESOURCE = 6;
1.8) int SOURCE_TYPE_DATA = 7;
1.9) int SOURCE_TYPE_QUALIFIED_RESOURCE = 8;
2)decodeOption:解码的参数,如bitmapConfig
3)ResizeOption:request的width&height等参数
4)RotationOption:旋转参数
5)progressiveRenderingEnable:是否开启渐进式渲染
6)RequestPriority(3个等级):本次请求的优先级
7)isDiskCacheEnable:本次请求是否要进行DiskCache
8)RequestListener:请求的listener
3.5 ImagePipeline
ImagePipeline是真正的数据获取的工作和管理者,它是单例的,通是顾名思义,其是一种管道的设计结构。它将自己的整个工作流程划分成一个个独立完成的工作单元Producer,每个工作单元有着相同的输入和输出接口。ImagePipeline根据不同的场景对这些Producer进行配置,从而生成相应的工作流管道。
图3.3 管道组织结构
3.5.1 ImagePipeline主要流程
图3.4 主要流程图(FROM 官方文档)
3.5.2内存结构
其内存Btimap内存缓存,EncodeCache编码数据内存缓存和Disk缓存。其中Btimap内存缓存使用的是Java堆的内存,EncodeCache和Disk中用到的内存都是Native的内存,不占用JAVA的堆内存。
图3.5 内存模块组成
3.5.3 线程池
默认的线程池配置如下:
- 3个线程网络下载
- 2个线程磁盘操作,读写
- 2个线程CPU操作:解码,转换,后处理等
3.5.4 一次完整的Net请求过程
图3.6 完整的Net请求过程
下面我们分别简单介绍一下每个producer都负责做了什么。
No.1 NetworkFetcherProducer
1)http请求(可配置)
2)output=>EncodeImage(ByteBuf)
3)Native 内存
No.2 WebTranscodeProducer
1)针对Webp格式图片
2)如果当前平台不支持,将其转为静态图片(JPEG/PNG)
No3. DiskCacheWriter Producer
1)DiskCache Enable is True(每个request可以配置)
2)Key默认是URI
3)文件管理方式URI=>HASH=>ResourceId
ResourceId%100分片划分到不同的文件夹
以ResourceId为文件名称存储
4)新起子线程进行工作
No4. MediaVariationsFallback Producer
MediaVariationsFallback是fresco提供的一种特殊用途。它提供可以使用一个MediaId(其实就是一个string)作为key来标识一组图片集合(a,b,c,d...)。当然这个模块起作用的前提是在imagerequest中定义MediaVariations和ResizeOptions.比如此次我们请求的是“MediaId”标识的集合中的a图片,但是在diskReader中没有找到此图片,此时我们在MediaVariationsFallback中就会去找同样用“MediaId”标识的(b,c,d。。。)其它图片,如果这些其它图片在diskcache中存在,且其大小符合ResizeOptions的要求,我们就会把在其它图片集合中找到的这张图片作为最终结果返回回去。
No5. DiskCacheRead Producer
1)从DiskCache中查找
No6. EncodeMemoryCache Producer
1)KEY->URI
2)get/put EncodeMemoryCache
No7. EncodeCacheKeyMultiplex Producer
1)KEY->URI+RequestLevel
2)用key聚合相同请求
No8. AddImageTransformMetaData Producer
- Meta解析
No9. ResizeAndRotate Producer
1)针对JPEG
2)根据request中的resizeOption和RotationOption参数对JPEG缩放和旋转
3)使用的是LibJpeg-turbo_1.5.0
No10. Decoder Producer
1)JPEG=>BITMAP
2)Gif
3)webp-Animate
No11. BitmapMemoryCache Producer
1)Key=Uri+ResizeOption+RotaionOption+DecodeOption
2)put/get BitmapMemoryCache
No12. BitmapMemoryCacheKeyMultiplex Producer
1)key=BitmapKey+request Level
2)聚合相同的BitmapMemoryCacheKey请求
No13. ThreadHandOff Producer
1)分发请求到工作线程
No13. BitmapMemoryCacheGet Producer
1)getCache
4 性能特性优点
1,内存做了大量优化,尽量复用Bitmap内存,减少java堆内存的申请,降低GC频率。
a)closeableReference=>Bitmap,采用了类似C++中的智能指针来管理Bitmap的使用,更精确的控制Bitmap这种大内存的。
b)BitmapPool
c)ByteBufPool
d)Native内存
2,引入生命周期控制
5 问题
1)invisible view
不可见view,是不会真正去启动其加载流程的。如前面讲的生命周期的控制。
2)wrapContent
如果width和height都设置成为wrapContent,是看不到view的显示的,因为drawableHierarchy的topLeveldrawable默认的getIntrinsicWidth和getIntrinsicHeight都是返回的“-1”,所以view在这种情况是没有实际意义的高宽的。至于为什么fresco不处理这种情况,其在它的官方文档中做了解释。
所以一般我们是要给view设置一个具体得大小,或者至少在高宽一个维度上给一个确定值,然后设置宽高比,让其按宽高比自己去设置另一个未设置的维度。
6 实际中的使用
Github上的源码中给了很多示例的代码和与其它加载框架对比的例子,可以参考。具体在使用方面主要总结有如下一些方面:
1)预加载图片
2)Gif图片
3)圆角图片,虚化,region,Scale Type,Resize
4)Progressive Jpeg
5)Webp/SVG