一、目的:
对比现在主流图片框架的优势和缺点,在实际项目中如何选择适合自己的框架;
主流框架
Glide、Fresco、Picasso、ImageLoader
共同优点:
- 使用简单;
- 可配置度高,自适应程度高;
- 多级缓存;
- 支持多种数据源;
- 丰富的图片格式;
- 支持多种Displayer(显示目标);
简单对比
框架 | Glide | Fresco | Picasso | ImageLoader |
---|---|---|---|---|
创建时间 | 2012 | 2015 | 2013 | 2011(已停止维护) |
作者 | Google员工开源项目 | FaceBook开源项目 | Square开源项目 | nostra13 |
默认图片格式 | RGB_565 | ARGB_8888 | ARGB_8888 | ARGB_8888 |
支持图片格式 | 支持Gif、WebP | 支持Gif、WebP | 不支持Gif、WebP | 不支持Gif、WebP |
支持Acitivity、Fragment生命周期 | 支持 | 不支持 | 不支持 | 不支持 |
OOM | 特大图 | 在5.0以下系统,Bitmap缓存位于ashmem (下面有介绍),这样Bitmap对象的创建和释放将不会引发GC,更少的GC会使你的App运行得更加流畅。5.0及其以上系统,相比之下,内存管理有了很大的改进,所以Bitmap缓存直接位于Java的heap (下面有介绍)上 |
特大图 | 低端手机、特大图 |
包大小 | 474K | 16.8M | 120k | 162k |
总结 | 使用大部分App,对图片要求不高,不需要高清原图可以考虑使用 | 对图片要求高,需要高清原图,建议使用 | 没有Glide支持和扩展好 | 不建议使用(已停止维护) |
以上名词介绍
Java Heap(Dalvik Heap):
这部分的内存区域是由Dalvik虚拟机管理,通过Java中 new 关键字来申请一块新内存。这块区域的内存是由GC直接管理,能够自动回收内存。这块内存的大小会受到系统限制,当内存超过APP最大可用内存时会OOM
Native Heap:
这部分内存区域是在C++中申请的,它不受限于APP的最大可用内存限制,而只是受限于设备的物理可用内存限制。它的缺点在于没有自动回收机制,只能通过C++语法来释放申请的内存
Ashmem(Android匿名共享内存):
这部分内存类似于Native内存区,但是它是受Android系统底层管理的,当Android系统内存不足时,会回收Ashmem区域中状态是 unpin 的对象内存块,如果不希望对象被回收,可以通过 pin 来保护一个对象
二、基本概念
在分析他们的差异、优缺点之前,我们先了解图片缓存通用的概念:
- RequestManager:请求生成和管理模块;
- Engine:引擎部分,负责创建任务(获取数据),并调度执行;
- GetDataInterface:数据获取接口,负责从各个数据源获取数据;
比如:MemoryCache内存缓存获取数据、DiskCache本地缓存获取数据、NetCache下载器从网络获取数据等等; - Displayer:资源显示器,用于显示和操作资源;
比如:ImageView,图片框架缓存不仅仅支持ImageView,同时还要支持其他View以及虚拟的Displayer概念,方便用去扩展自己的需求; - Processor:资源处理器,负责处理资源;
比如:选择、压缩、截取、圆角等处理;
以上概念在不同框架之间可能不同,比如Displayer在ImageLoader中叫做ImageAware,在Picasso和Glide中叫做Target。
三、设计分析
3.1 Glide
![](https://img.haomeiwen.com/i17942410/749a3e7d2760f493.png)
Glide设计及流程
以上为Glide的总体设计图。
整个库分为RequestManager(请求管理器)、Engine(数据获取引擎)、Fetcher(数据获取器)、MemoryCache(内存缓存)、DiskLRUCache(本地缓存)、Transformation(图片处理)、Encoder(编码处理)、Registry(图片类型以及解析器配置)、Target(目标)等模块。
简单流程:Glider收到加载及显示资源任务,创建Request并将它交给RequestManager,Request启动Engine去数据源获取资源,得到资源后通过Transformation处理后交给Target.
Glide依赖DiskLRUCache、GifDecoder等开源库去完成本地缓存和Gif图片解密工作;
Glide核心
为Bitmap 维护一个BitmapPool对象池, 对象池的主要目的是通过减少大对象的分配以重用来提高性能!
Glide优点
- 加载速度快,框架体积小,4、5百kb
- 图片缓存->媒体缓存:Glide不仅是一个图片缓存,它支持Gif、WebP、缩略图。甚至是Video,所以更该当做一个媒体缓存。
- 支持优先级处理
- 支持Activity、Fragment生命周期一致,支持trimMenory:Glide对每个context都保存一个RequestManager,通过FragmentTransaction保存于Activity、Fragment生命周期一致,并且有对应的trimMemory接口实现可供调用;
- 支持Okhttp、Volley:Glide默认通过UrlConnection获取数据,可以配合Okhttp或者Volley获取。
-
内存友好:
①Glide内存缓存有一个active设计
从内存缓存中获取数据时,不像一般实现用get,而是用remove,在将这个缓存数据放到一个value为软引用的activeResources map中,并计数引用数,在图片加载完后进行判断,如果引用数为空则回收掉;
②内存缓存更小图片
Glide以url、view_width、view_height、屏幕分辨率等作为联合key,将处理后图片缓存在内存缓存中,而不是原始图片以节省大小
③图片默认使用RGB_565,而不是ARGB_888;
其他:Glide可以通过signature或不使用本地缓存,支持url过期;
缺点:
①图片质量低:因为机制不同,速度快,但是图片的质量降低了RGB565;
②多尺寸缓存导致内存和磁盘占用多:根据ImageView大小来缓存,可能会导致一张图片可能根据展示情况来缓存不同尺寸的几份;
扩展理解参考:https://www.jianshu.com/p/1ab5597af607
3.2 Picasso
![](https://img.haomeiwen.com/i17942410/8b35e91c6672af6b.png)
Picasso设计及流程
以上为Picasso的总体设计图。
整个库分为Dispatcher、RequestHandler以及Downloader、PicassoDrawable等模块。
简单流程:Picasso收到加载显示图片任务后,创建Request并将它交给Dispatcher,Dispatcher分发任务到具体RequestHandler,任务通过MemoryCache及Handler(数据获取接口)获取图片,图片获取成功后通过PicassoDrawable显示到Target中;
上面Data的File system部分,Picasso没有自定义本地缓存的接口,默认使用http的本地缓存,API19以上使用okhttp,一下使用UrlConnection,所以如果需要自定义本地缓存就需要自定义Downloader;
Picasso优点
- 图片质量高ARGB_8888,体积小可以配合OKhttp使用
- 自带统计监控功能:支持图片缓存使用的监控,包括缓存命中率、已使用内存大小、节省的流程等。
- 支持优先级处理:每次任务调度前会选择优先级高的任务,比如App页面中的Banner的优先级高于Icon时就很适用
- 支持延时到图片尺寸计算完成加载
-
支持飞行模式、并发线程数据根据网络类型而变
手机切换到飞行模式或网络类型变换时,会自动调整线程池最大并发数,比如wifi最大并发为4,4G为3,3G为2。
这里Picasso根据网络类型来决定最大并发数,而不是CPU核数。 -
“无”本地缓存
无本地缓存并不是说没有本地缓存,而是Picasso自己没有实现,交给了Square的另外有一个网络库okhttp去实现,这样的好处是可以通过请求Response Header中的Cache-Control及Expired控制图片的过期时间。
缺点:加载速度没有其他框架快;
特点:只缓存一个全尺寸的图片,根据需求的大小在压缩转换;
3.2 Fresco
![](https://img.haomeiwen.com/i17942410/7fbfd3cd4717c85f.png)
Fresco设计及流程
以上为Fresco的总体设计图
整个库分为UI:DraweeView(View控件)、Drawable(图片数据)、DraweeController(图片控制器)、DraweeHiierarchy(图片体系);Core:DataSource(数据源)、ImagePipeline(图像管道)、Producer(生产者)、ProducerFacotry(生产工厂)、Subcriber(订阅)、Supplier(供应者)、Consumer(消费者);IO/Data:MemoryCache(内存缓存)、Network、DiskCache(磁盘缓存)、Recourse(本地资源)
简单流程:从上面的结构可以看出,fresco主要采用了工厂+建造者的模式实现功能,逻辑划分比较清楚;Fresco框架整体是一个MVC模式,DrawableView--->View用来显示顶层视图、DrawableController--->Control控制加载图片的配置 事件的分发、DrawableHierarchy--->Model 用于存储和描述图片信息,同时也封装了一些图片的显示和视图层级的方法;ImagePipeline模块负责从网络、本地文件系统、本地资源加载图片
Fresco优点
- 图片的渐进式呈现
- 良好的内存管理,低端机一样出色
- 支持动图加载:加载Gif、WebP动图,每一帧都是一张很大的Bitmap,每个动画都有很多帧。Fresco能管理好每一帧并管理好你的内存
- 丰富的图片处理:缩放、圆角、透明、高斯模糊等处理
- 支持监听下载事件:
-
系统底层C(匿名共享内存)缓存,避免OOM:
在系统底层C开辟内存区域处理缓存(匿名共享内存),避免占用应用内存资源,不会因为图片加载而导致OOM,减少Bitmap频繁回收导致的卡顿,性能更高(内存管理方便:主要看两个内容,既java堆和native堆。Java对最大值受设备限制(进程资源限制),并且其内存回收是个麻烦事,其进行回收时会直接影响前端性能响应。Native堆是通过C++来写的,能获取更多的内存,内存管理也更加灵活,但也相当麻烦);
缺点:
①框架大,影响Apk体积;
②一定的学习成本,使用比较繁琐,需要使用内部提供的ImageView控件,使用起来比较复杂;
网友评论