Android图片框架对比
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android图片框架对比相关的知识,希望对你有一定的参考价值。
参考技术A对比现在主流图片框架的优势和缺点,在实际项目中如何选择适合自己的框架;
Glide、Fresco、Picasso、ImageLoader
共同优点:
以上名词介绍
在分析他们的差异、优缺点之前,我们先了解图片缓存通用的概念:
以上概念在不同框架之间可能不同,比如Displayer在ImageLoader中叫做ImageAware,在Picasso和Glide中叫做Target。
以上为Glide的总体设计图。
整个库分为RequestManager(请求管理器)、Engine(数据获取引擎)、Fetcher(数据获取器)、MemoryCache(内存缓存)、DiskLRUCache(本地缓存)、Transformation(图片处理)、Encoder(编码处理)、Registry(图片类型以及解析器配置)、Target(目标)等模块。
简单流程: Glider收到加载及显示资源任务,创建Request并将它交给RequestManager,Request启动Engine去数据源获取资源,得到资源后通过Transformation处理后交给Target.
Glide依赖DiskLRUCache、GifDecoder等开源库去完成本地缓存和Gif图片解密工作;
为Bitmap 维护一个BitmapPool对象池, 对象池的主要目的是通过减少大对象的分配以重用来提高性能!
缺点 :
①图片质量低:因为机制不同,速度快,但是图片的质量降低了RGB565;
②多尺寸缓存导致内存和磁盘占用多:根据ImageView大小来缓存,可能会导致一张图片可能根据展示情况来缓存不同尺寸的几份;
扩展理解参考: https://www.jianshu.com/p/1ab5597af607
以上为Picasso的总体设计图。
整个库分为Dispatcher、RequestHandler以及Downloader、PicassoDrawable等模块。
简单流程: Picasso收到加载显示图片任务后,创建Request并将它交给Dispatcher,Dispatcher分发任务到具体RequestHandler,任务通过MemoryCache及Handler(数据获取接口)获取图片,图片获取成功后通过PicassoDrawable显示到Target中;
上面Data的File system部分,Picasso没有自定义本地缓存的接口,默认使用http的本地缓存,API19以上使用okhttp,一下使用UrlConnection,所以如果需要自定义本地缓存就需要自定义Downloader;
缺点 :加载速度没有其他框架快;
特点 :只缓存一个全尺寸的图片,根据需求的大小在压缩转换;
以上为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模块负责从网络、本地文件系统、本地资源加载图片
缺点:
①框架大,影响Apk体积;
②一定的学习成本,使用比较繁琐,需要使用内部提供的ImageView控件,使用起来比较复杂;
Glide 系列 图片加载框架对比
本文主要比对框架包括:Universal Imageloader(下文简称 UIL)、Picasso、 Glide、Fresco。先对各个框架做简单介绍,再对框架进行对比。
简介篇
UIL
UIL 是一个老牌的图片加载框架,旨在提供一个强大的、灵活的和高度可定制的工具,以实现图像加载、缓存和显示功能。 UIL 支持多线程图片加载,支持占位图和错误图、支持图片下载进度的监听,支持缓存不同尺寸图片,支持图片内存缓存和硬盘缓存,支持自定义图片加载格式,支持 ListView或者 GridView 滚动时暂停加载。但 UIL 不支持动图展示,且该框架的作者已经宣布不在对其进行维护。
ImageLoader.getInstance()
.displayImage("http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg", ivImg, null);
Picasso
Picasso 其名字来源于画家毕加索,是著名开源公司 Square 的作品,与 OkHttp 和 Retrofit 合称开发三件套。Picasso 同样支持占位图和错误图展示,支持图形变换操作,支持内存和硬盘缓存,支持加载本地或者网络资源,比较有特色的是其拥有统计功能,可以知道一共使用了多少内存,缓存命中率, 图片来自内存还是硬盘等。Picasso 使用起来也是简单方便,基本上一行代码可解决显示图片请求。
Picasso.with(context)
.load("http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg")
.into(ivImg);
Glide
Glide 是一个 Google 官方推荐的快速高效的图片加载库,主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑。 Glide 提供了简单易用的API,典型流式语法风格,大部分展示图片需求可以一行代码搞定。Glide 的 API 还特别灵活,在支持开发者自定义配置和模块的同时又和其加载图片的逻辑没有任何交集,是一种低耦合的编程方式的实现。默认情况下,通信组件使用 HttpUrlConnection,但也提供了 Volley 和 OkHttp 快速集成的工具。
Glide.with(fragment).load(url).into(imageView);
Glide使用了多个步骤来确保在Android上加载图片尽可能的快速和平滑:
自动、智能的下采样(downsampling)和缓存(caching),以最小化存储开销和解码次数;
积极的资源重用,例如字节数组和Bitmap,以最小化昂贵的垃圾回收和堆碎片影响;
深度的生命周期集成,以确保仅优先处理活跃的 Fragment 和 Activity 的请求,并有利于应用在必要时释放资源以避免在后台时被杀掉。
Glide 还支持播放短视频,其生命周期的集成是 Glide 的一大特色。
Fresco
Fresco 是一个强大的图片加载组件,其设计中有一个叫做 Image Pipeline 的模块,负责从网络、本地文件系统、本地资源加载图片。为了最大限度节省空间和CPU时间,它含有 3 级缓存设计(2级内存,1级磁盘)。还有一个叫做 Drawees 的模块,它会在图片加载完成前显示占位图,加载成功后自动替换为目标图片。当图片不再显示在屏幕上时,它会及时地释放内存和空间占用。
Fresco 包含以下特性:
内存管理:在 Andrid 5.0 以下系统,Fresco 会将图片放到 ASM(Anonymous Shared Memory,匿名共享内存)区域,减少了低性能手机上 OOM 的发生。在图片不用时,应该显式释放这部分资源,SimpleDraweeView 自动处理了这个释放过程。在 5.0 及以上版本系统,由于 Android 对其内存管理做了很大优化,Bitmap 缓存位于 Java 堆区,同样避免了 OOM 的发生。
图片加载:Image Pipeline 允许你用多种方式来定义图片的加载过程图片可以来自远程服务器,本地文件,或者Content Provider,本地资源。压缩后的文件缓存在本地存储中,Bitmap数据缓存在内存中。
图片绘制:可自定义占位图或者进度条,自定义 overlay,现在失败后的点击重试等。
图片渐进式呈现:Android 本身的图片库不支持此格式,但是Fresco支持渐进式图片。渐进式格式先呈现大致的图片轮廓,然后随着图片下载的继续,呈现逐渐清晰的图片,对于移动设备,尤其是慢网络有极大的利好,可带来更好的用户体验。
友好的支持 Gif 图片和 Webp 动图。
Fresco 使用时需要用其框架定义的组件,且明确指定尺寸 或者用 match_parent 标注。
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="130dp"
android:layout_height="130dp"
fresco:placeholderImage="@drawable/my_drawable"
/>
Uri uri = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/logo.png");
SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);
draweeView.setImageURI(uri);
对比篇
共同特性
支持占位图或者加载错误图
支持 图像变换,如 裁剪、尺寸修改、方圆转换等
可配置度高,图片缓存的内存缓存、本地缓存、线程池、缓存算法等大都可轻松配置。
自适应程度高,根据系统性能初始化缓存配置、系统信息变更后动态调整策略。比如根据 CPU 核数确定最大并发数,根据可用内存确定内存缓存大小,网络状态变化时调整最大并发数等。
多级缓存,都至少有二级缓存,提高图片的加载速度
支持多种数据源,如网络、本地、Assets等
支持多种 Displayer,支持自定义的 Displayer 概念。
支持配置图片格式,如配置 ARGB8888、RGB565 等
对比表格
磁盘缓存
我们先啰嗦两句,来看一下存储器的层次结构,简单分为:寄存器、高速缓存、主存、本地磁盘。
此图由上到下数据访问速度在逐层降低,从内存读取数据的速度远远大于从硬盘读取数据,从硬盘读取数据的速度远远大于从网络访问数据的速度,且网络访问还有可能失败。寄存器、高速缓存这两层对于我们 app 开发者来说是透明的,无需考虑,我们只需将内存缓存和硬盘缓存利用起来就可以了。基本上所有的图片加载框架都是在内存和硬盘这两个层次上做的数据缓存。内存缓存作为第一级缓存,可以避免将同一张图片重复加载到内存;硬盘缓存作为第二级缓存,可以避免重复下载同一张网络图片。
我们知道 ImageView 在显示图片时只是起一个容器的作用,里面放置的图片是 一个由像素组成的二维矩阵。既然是一个容器,那图片大小可能大于容器,也可能小于容器,所以才有了 ImageView 的 scaleType 属性。当图片大于容器时,可以将图片压缩,裁剪;当图片小于容器时既可以放大填充容器,也可以不做任何事情。且图片在硬盘中的大小并不等于在内存中的大小。图片在内存中的大小取决于其编码格式。许多图片加载框架会根据 ImageView 大小对图片做缩略处理,这样既保证了清晰度又减少了内存耗用。
全尺寸 指 url 对应的图片,实际尺寸为 ImageView 尺寸相同的图片。对于 Picasso,不管 ImageView 如何变换大小,只会缓存一个全尺寸的图片。对于 Glide、UIL、Fresco 都支持缓存同一图片的不同尺寸。对同一张图片缓存不同尺寸意味着需要更大的缓存空间,但同时也能提供了更快的展示速度,此处就是用空间换取时间,省去了每次显示之前将图片重新调整大小的时间。所以缓存多尺寸的图片框架会相较于缓存原始尺寸的更加快,但由于占据了更多的空间,这一点可以按需设置。
图片格式
不论采用哪个框架,同一张图片其显示质量取决于图片在内存中的格式,与框架无关。这四个框架都支持配置图片格式。格式清晰度从高到低如下:
ARG_B8888 >RGB_565 > ARGB_4444 >ALPHA_8
附:在这对图片格式做一个简单介绍:其中 A,代表透明度;R,代表 Red, 红色;G,代表 Green,绿色;B,代表 Blue,蓝色。
ALPHA_8,代表像素只有透明度信息,没有颜色信息,一个像素占 8 bit,即 1 Byte。
RGB_565,代表像素只有颜色信息,没有透明度信息,其中 R 占用 5 bit,G 占用 6 bit,B 占用 5 bit,一个像素大小为 5+6+5=16 bit ,即 2 Byte。
ARGB_4444,代表像素既有透明度信息,也有颜色信息,其中 A 占用 4 bit,R 占用 4 bit,G 占用 4 bit,B 占用 4 bit,一个像素大小为 4+4+4+4=16 bit ,即 2 Byte。
ARGB_8888,代表像素既有透明度信息,也有颜色信息,其中 A 占用 8 bit,R 占用 8 bit,G 占用 8 bit,B 占用 8 bit,一个像素大小为 8+8+8+8=32 bit ,即 4 Byte。
这几个字段在 Android 源码 Bitmap.Config 有中定义,可以看到 ARG_B8888 格式是占用空间最大的,一个像素点要占用 4 Byte 内存,由于保存了更多的图片细节信息,所以此格式也是显示图片最清晰的。ARGB_4444 和 RGB_565 占用内存为 ARG_B8888 的一半。ARGB_4444 虽然设计理念是为了保留透明度的同时又节省内存,但由于其显示的图像质量太差而遭到弃用。RGB_565 和 ARG_B8888 是最为通用的两种图片格式,可以按需选取。如果必须保留图片的透明度信息,则建议使用 ARG_B8888, 如果 APP 内存吃紧同时对透明度没有要求的话,可使用 RGB_565。
包体积
UIL 和 Picasso 包体积较小,对安装包影响不大。 Glide 包体积略大。其方法数较多,使用时可能会遇到 65k 问题。 Fresco 包体积略大,若按照正确步骤使用了 Fresco,引入后发布包的体积应当不会增加 500Kb。用户可以根据自己需求有选择的添加动画依赖库和 WebP 支持包,这种模块化机制使得基础 Fresco 库很轻,增加一个库大约包体积会增加 100 KB。
如何选择图片加载框架
UIL:建议弃用,除非你的项目一直在用 UIL 且框架迁移成本(时间成本)比较大,否则不建议使用或沿用。因为官方已经不再对其维护,并且由于其不支持动图,若 app 有动图需求的话还需引入其他图片框架,增加应用体积,还不如一步到位。
Picasso:不建议使用,Glide 是 Picasso 的加强版,可以说它的目的就是为了取代 Picasso,所以在 Glide 和 Picasso 之间选择,优先推荐 Glide 。
Glide vs Fresco:这两个框架性能不分伯仲,都可以减少 OOM 的发生。Glide 注重于平滑的滚动,善于处理大型的图片流,Glide还支持播放短视频,有此需求的话 Glide 为不二之选,另外 Glide 还有一个隐藏的优点,它是 Google 官方推荐的框架,所以相对于后期维护成本来说更低一些。Fresco 的优点是内存管理,尤其是在 5.0 以下的系统中优化做的非常好,将图片放在 ASM 中。其缺点也很明显,包的体积太大,其在图片多的应用中更能体现其价值。Fresco 对代码的侵入性可能会更高一些,由于所有的View 组件需要继承自一个基类 DraweeView ,需指定明确尺寸或者用 match_parent 来布局(为了更好的用户体验,解决占位图和真实图尺寸大小不匹配导致UI跳跃的问题),如果你是一个新项目,可以考虑用 Fresco。
总结:框架只在 Glide 和 Fresco 中选择,Glide 由于是 Google 官方推荐的框架,所以是开发者的首选。如果你是一个新项目且对包体积没有要求的话也可以尝试 Fresco。
附:
http://blog.csdn.net/zivensonice/article/details/51822968
http://www.mamicode.com/info-detail-929571.html
这两个链接是对各个框架加载图片时堆内存、本地内存、加载时间、请求次数的对比,有兴趣的可以自己参考下。笔者个人感觉参考性不是很大,在多个机型测试结果不稳定,及同机型上框架切换时数据变化慢。现在 Android Studio 3.0 版本有 Android Profiler,可以点开观察内存情况,这个只支持5.0版本以上的手机哦。
参考文献
https://www.fresco-cn.org/ https://github.com/bumptech/glide/wiki http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0327/2650.html
以上是关于Android图片框架对比的主要内容,如果未能解决你的问题,请参考以下文章
Android从零单排系列九《Android视图控件——ImageView》
Android从零单排系列九《Android视图控件——ImageView》
Android从零单排系列九《Android视图控件——ImageView》