Andoird 图片加载框架区别

来源:互联网 发布:手机编程序软件 编辑:程序博客网 时间:2024/04/25 21:45
1.哪三大图片加载框架?        1)    Picasso        2)    Glide        3)    Fresco2.介绍:    Picasso :和Square的网络库一起能发挥最大作用,因为Picasso可以选择将网络请求的缓存部分交给了okhttp实现。    Glide:模仿了Picasso的API,而且在他的基础上加了很多的扩展(比如gif等支持),Glide默认的Bitmap格式是RGB_565,比    Picasso默认的ARGB_8888格式的内存开销要小一半;Picasso缓存的是全尺寸的(只缓存一种),而Glide缓存的是跟ImageView尺寸相同的(即56*56128*128是两个缓存) 。    FB的图片加载框架Fresco:最大的优势在于5.0以下(最低2.3)的bitmap加载。在5.0以下系统,Fresco将图片放到一个特别的内存区域(Ashmem区)。当然,在图片不显示的时候,占用的内存会自动被释放。这会使得APP更加流畅,减少因图片内存占用而引发的OOM。为什么说是5.0以下,因为在5.0以后系统默认就是存储在Ashmem区了。3.总结:       Picasso所能实现的功能,Glide都能做,无非是所需的设置不同。但是Picasso体积比起Glide小太多如果项目中网络请求本身用的就是okhttp或者retrofit(本质还是okhttp),那么建议用Picasso,体积会小很多(Square全家桶的干活)。Glide的好处是大型的图片流,比如gif、Video,如果你们是做美拍、爱拍这种视频类应用,建议使用。Fresco在5.0以下的内存优化非常好,代价就是体积也非常的大,按体积算Fresco>Glide>Picasso不过在使用起来也有些不便(小建议:他只能用内置的一个ImageView来实现这些功能,用起来比较麻烦,我们通常是根据Fresco自己改改,直接使用他的Bitmap层)

一. 四大图片缓存基本信息

img

Universal ImageLoader 是很早开源的图片缓存,在早期被很多应用使用。

Picasso 是 Square 开源的项目,且他的主导者是 JakeWharton,所以广为人知。

Glide 是 Google 员工的开源项目,被一些 Google App 使用,在去年的 Google I/O 上被推荐,不过目前国内资料不多。

Fresco 是 Facebook 在今年上半年开源的图片缓存,主要特点包括:

  1. 两个内存缓存加上 Native 缓存构成了三级缓存;
  2. 支持流式,可以类似网页上模糊渐进式显示图片;
  3. 对多帧动画图片支持更好,如 Gif、WebP。

鉴于 Fresco 还没发布正式的 1.0 版本,同时一直没太多时间熟悉 Fresco 源码,后面对比不包括 Fresco,以后有时间再加入对比。

二、基本概念

在正式对比前,先了解几个图片缓存通用的概念:

  1. RequestManager:请求生成和管理模块;
  2. Engine:引擎部分,负责创建任务(获取数据),并调度执行;
  3. GetDataInterface:数据获取接口,负责从各个数据源获取数据。 比如 MemoryCache 从内存缓存获取数据、DiskCache 从本地缓存获取数据,下载器从网络获取数据等。
  4. Displayer:资源(图片)显示器,用于显示或操作资源。 比如 ImageView,这几个图片缓存都不仅仅支持 ImageView,同时支持其他 View 以及虚拟的 Displayer 概念。
  5. Processor 资源(图片)处理器, 负责处理资源,比如旋转、压缩、截取等。

以上概念的称呼在不同图片缓存中可能不同,比如 Displayer 在 ImageLoader 中叫做 ImageAware,在 Picasso 和 Glide 中叫做 Target。

三、共同优点

1. 使用简单 
都可以通过一句代码可实现图片获取和显示。

2. 可配置度高,自适应程度高 
图片缓存的下载器(重试机制)、解码器、显示器、处理器、内存缓存、本地缓存、线程池、缓存算法等大都可轻松配置。

自适应程度高,根据系统性能初始化缓存配置、系统信息变更后动态调整策略。 
比如根据 CPU 核数确定最大并发数,根据可用内存确定内存缓存大小,网络状态变化时调整最大并发数等。

3. 多级缓存 
都至少有两级缓存、提高图片加载速度。

4. 支持多种数据源 
支持多种数据源,网络、本地、资源、Assets 等

5. 支持多种 Displayer 
不仅仅支持 ImageView,同时支持其他 View 以及虚拟的 Displayer 概念。

其他小的共同点包括支持动画、支持 transform 处理、获取 EXIF 信息等。

四、ImageLoader 设计及优点

img 

1. 总体设计及流程

上面是 ImageLoader 的总体设计图。整个库分为 ImageLoaderEngine,Cache 及 ImageDownloader,ImageDecoder,BitmapDisplayer,BitmapProcessor 五大模块,其中 Cache 分为 MemoryCache 和 DiskCache 两部分。

简单的讲就是 ImageLoader 收到加载及显示图片的任务,并将它交给 ImageLoaderEngine,ImageLoaderEngine 分发任务到具体线程池去执行,任务通过 Cache 及 ImageDownloader 获取图片,中间可能经过 BitmapProcessor 和 ImageDecoder 处理,最终转换为Bitmap 交给 BitmapDisplayer 在 ImageAware 中显示。

2. ImageLoader 优点

(1) 支持下载进度监听

(2) 可以在 View 滚动中暂停图片加载 
通过 PauseOnScrollListener 接口可以在 View 滚动中暂停图片加载。

(3) 默认实现多种内存缓存算法 这几个图片缓存都可以配置缓存算法,不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等。

(4) 支持本地缓存文件名规则定义

五、Picasso 设计及优点

img 

1. 总体设计及流程

上面是 Picasso 的总体设计图。整个库分为 Dispatcher,RequestHandler 及 Downloader,PicassoDrawable 等模块。

Dispatcher 负责分发和处理 Action,包括提交、暂停、继续、取消、网络状态变化、重试等等。

简单的讲就是 Picasso 收到加载及显示图片的任务,创建 Request 并将它交给 Dispatcher,Dispatcher 分发任务到具体 RequestHandler,任务通过 MemoryCache 及 Handler(数据获取接口) 获取图片,图片获取成功后通过 PicassoDrawable 显示到 Target 中。

需要注意的是上面 Data 的 File system 部分,Picasso 没有自定义本地缓存的接口,默认使用 http 的本地缓存,API 9 以上使用 okhttp,以下使用 Urlconnection,所以如果需要自定义本地缓存就需要重定义 Downloader。

2. Picasso 优点

(1) 自带统计监控功能 
支持图片缓存使用的监控,包括缓存命中率、已使用内存大小、节省的流量等。

(2) 支持优先级处理 
每次任务调度前会选择优先级高的任务,比如 App 页面中 Banner 的优先级高于 Icon 时就很适用。

(3) 支持延迟到图片尺寸计算完成加载

(4) 支持飞行模式、并发线程数根据网络类型而变 
手机切换到飞行模式或网络类型变换时会自动调整线程池最大并发数,比如 wifi 最大并发为 4, 4g 为 3,3g 为 2。 
这里 Picasso 根据网络类型来决定最大并发数,而不是 CPU 核数。

(5) “无”本地缓存 
无”本地缓存,不是说没有本地缓存,而是 Picasso 自己没有实现,交给了 Square 的另外一个网络库 okhttp 去实现,这样的好处是可以通过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过期时间。

六、Glide 设计及优点

img 

1. 总体设计及流程

上面是 Glide 的总体设计图。整个库分为 RequestManager(请求管理器),Engine(数据获取引擎)、Fetcher(数据获取器)、MemoryCache(内存缓存)、DiskLRUCache、Transformation(图片处理)、Encoder(本地缓存存储)、Registry(图片类型及解析器配置)、Target(目标)等模块。

简单的讲就是 Glide 收到加载及显示资源的任务,创建 Request 并将它交给RequestManager,Request 启动 Engine 去数据源获取资源(通过 Fetcher ),获取到后 Transformation 处理后交给 Target。

Glide 依赖于 DiskLRUCache、GifDecoder 等开源库去完成本地缓存和 Gif 图片解码工作。

2. Glide 优点

(1) 图片缓存->媒体缓存 
Glide 不仅是一个图片缓存,它支持 Gif、WebP、缩略图。甚至是 Video,所以更该当做一个媒体缓存。

(2) 支持优先级处理

(3) 与 Activity/Fragment 生命周期一致,支持 trimMemory 
Glide 对每个 context 都保持一个 RequestManager,通过 FragmentTransaction 保持与 Activity/Fragment 生命周期一致,并且有对应的 trimMemory 接口实现可供调用。

(4) 支持 okhttp、Volley 
Glide 默认通过 UrlConnection 获取数据,可以配合 okhttp 或是 Volley 使用。实际 ImageLoader、Picasso 也都支持 okhttp、Volley。

(5) 内存友好 
① Glide 的内存缓存有个 active 的设计 
从内存缓存中取数据时,不像一般的实现用 get,而是用 remove,再将这个缓存数据放到一个 value 为软引用的 activeResources map 中,并计数引用数,在图片加载完成后进行判断,如果引用计数为空则回收掉。

② 内存缓存更小图片 
Glide 以 url、view*width、view*height、屏幕的分辨率等做为联合 key,将处理后的图片缓存在内存缓存中,而不是原始图片以节省大小

③ 与 Activity/Fragment 生命周期一致,支持 trimMemory

④ 图片默认使用默认 RGB*565 而不是 ARGB*888 
虽然清晰度差些,但图片更小,也可配置到 ARGB_888。

其他:Glide 可以通过 signature 或不使用本地缓存支持 url 过期

七、汇总

img

三者总体上来说,ImageLoader 的功能以及代理容易理解长度都一般。

Picasso 代码虽然只在一个包下,没有严格的包区分,但代码简单、逻辑清晰,一两个小时就能叫深入的了解完。

Glide 功能强大,但代码量大、流转复杂。在较深掌握的情况下才推荐使用,免得出了问题难以下手解决。

Glide^2 和 Picasso^1 都是 Android 世界中非常流行的图片加载函数库,Android 应用开发者在职业生涯中至少都应该用过其中一种。这两个函数库都提供了很多特性,经过优化,图片加载速度非常快,而且都在很多实际项目中通过了测试。从某种程度上面讲,Glide 是 Picasso 的一个变种,表面上看,它们的工作原理是一样的,但实际上,无论在图片的下载,缓存还是图片加载进内存的方式,这两个库都存在很大的区别。本文我们就来对比它们的主要区别,看看哪个库是应用开发中的最佳选择。

本文比较的是 Glide v3.7.0 和 Picasso v2.5.2,当你阅读本文时最新版本可能已经发生了变化。

函数库的导入

Picasso 和 Glide 都托管在 jcenter 中,因此,导入到工程中的方式差不多,Picasso 如下所示:

dependencies {    compile 'com.squareup.picasso:picasso:2.5.2'}

Glide 如下所示:

repositories {    mavenCentral() // jcenter() works as well because it pulls from Maven Central}dependencies {    compile 'com.github.bumptech.glide:glide:3.7.0'    compile 'com.android.support:support-v4:19.1.0'}

其中 Glide 依赖于 support-v4,但由于几乎所有项目都会依赖它,所以可以和项目现有的依赖版本共用。

包大小和方法数

从包大小方面看,Glide 差不多是 Picasso 的 3.5 倍,如下图所示:

1-rQe23b0xA6Fpd6zopjx2aQ.png-7.7kB

Picasso 的方法数是 849 个,而 Glide 方法数是 2678 个。这个数字对于 Android DEX 文件的 65535 方法数限制问题来说已经相当大了,在试用过程中一定要记得开启 ProGuard 进行混淆压缩。

1-SE-DjIHhPW8iwf4giJ66aA.png-8.1kB

语法

这两个函数库实现从指定 URL 地址加载图片并显示在 ImageView 上面的语法几乎是一样的,而且都支持渐变动画和基于中间的裁剪(Center Crop)。你当然也可以给 ImageView 设置加载时以及加载失败时的占位图。

Picasso 语法如下:

Picasso.with(context)    .load(url)    .centerCrop()    .placeholder(R.drawable.user_placeholder)    .error(R.drawable.user_placeholder_error)    .into(imageView);

Gilde 语法如下:

Glide.with(myFragment)    .load(url)    .centerCrop()    .placeholder(R.drawable.loading_spinner)    .crossFade()    .into(myImageView);

Glide 相比 Picasso 的一大优势是它可以和 Activity 以及 Fragment 的生命周期相互协作,我们在调用 Glide.with() 函数时可以将 Activity 或者 Fragment 的实例传进去,这样 Glide 就会自动将图片加载等操作和组件的生命周期例如 onPause()onResume() 关联起来。

with.png-7.2kB

磁盘缓存

这两个函数库都支持从指定 URL 地址将图片下载下来,并缓存到磁盘上,但两者缓存的策略有所不同。

Picasso 将图片下载后会不经压缩直接将图片整个缓存到磁盘中,当需要用到图片时,它会直接返回这张完整大小的图片,并在运行时根据 ImageView 的大小作适配。

Glide 的原理与之不同,它从指定 URL 地址下载图片后会首先根据 ImageView 的大小适配图片,然后将适配后的图片再存储到磁盘中。因此,如果你使用不同大小的 ImageView 加载同一张图片,Glide 将会以不同的分辨率缓存这张图片的两份不同的拷贝。这样可能会增加磁盘缓存的大小,当然好处也是有的,在后面我们会提到。

如前所述,当我们调整 ImageView 的大小时,Picasso 只会缓存完整大小的一张图片,而 Glide 会根据 ImageView 的大小分别缓存对应分辨率的图片。Glide 这种方法的缺点是即使这张图片已经在一个 ImageView 中加载过,如果另一个大小不同的 ImageView 也要加载这张图片,那么这张图片仍然需要重新走一遍流程:到指定的 URL 地址下载,然后根据 ImageView 大小适配,最后缓存到磁盘中。

当然,上面我们说的是默认情况,如果在使用 Glide 时不希望每次都去远程服务器下载完整大小的图片,那么在初始化时可以添加如下 diskCacheStrategy 配置:

Glide.with(myFragment)    .load(url)    .diskCacheStrategy(DiskCacheStrategy.ALL)    .into(myImageView);

这样配置后,Glide 下次从指定 URL 下载图片,会同时在磁盘上缓存完整的图片和经过大小适配后的图片,下次另一个大小不同的 ImageView 也要加载这张图片,Glide 会直接从磁盘获取完整大小的图片并进行大小适配,缓存后显示在这个 ImageView 中。

内存

默认情况下,Glide 将图片加载进内存时使用的是 RGB_565 的配置,而 Picasso 则使用 ARGB_8888 配置。因此,在对比两者内存占用大小时,为了公平起见我们通过继承 GlideModule 类,并将它加载图片时所用的格式由 RGB_565 修改为 ARGB_8888,类似如下代码所示:

public class MyGlideModule implements GlideModule {    @Override    public void applyOptions(Context context, GlideBuilder builder) {        builder.setDecodeFormat(DecodeFormat.ALWAYS_ARGB_8888);    }    @Override    public void registerComponents(Context context, Glide glide) {        //    }}

当然,为了使这个 GlideModule 生效,我们还需要将这个 GlideModule 在 proguard.pro 文件中 keep 住,如下所示:

-keepnames class com.asce1885.MyGlideModule// 更通用的方式如下:// -keep public class * implements com.bumptech.glide.module.GlideModule

接着在 AndroidManifest.xml 文件中注册这个 GlideModule,如下所示:

<manifest ...>    <!-- ... permissions -->    <application ...>        <meta-data            android:name="com.asce1885.MyGlideModule"            android:value="GlideModule" />        <!-- ... activities and other components -->    </application></manifest>

下图就是修改后分别使用 Glide 和 Picasso 在线加载图片时的内存占用:

1–TOjFF8NJ6W7bmHZycjDtw.png-12.5kB

可以看到,在加载同样配置的图片时,Glide 内存占用更少,这从前面的讨论中其实可以猜测到了,Picasso 是将完整大小的图片加载进内存,然后依赖 GPU 来根据 ImageView 的大小来适配并渲染图片,而 Glide 是针对每个 ImageView 适配图片大小后再存储到磁盘的,这样加载进内存的是压缩过的图片,内存占用自然就比 Picasso 要少。Glide 这种做法有助于减少 OutOfMemoryError 的出现。

图片加载的耗时

当从指定 URL 地址加载图片时,这两个函数库都会首先检查图片是否已经在缓存中,如果不存在才去 URL 地址中下载。当我们从远程 URL 地址下载图片时,Picasso 相比 Glide 要快很多。可能的原因是 Picasso 下载完图片后直接将整个图片加载进内存,而 Glide 还需要针对每个 ImageView 的大小来适配压缩下载到的图片,这个过程需要耗费一定的时间。(当然我们可以使用 thumbnail() 来减少压缩的时间,后面会讨论到)

1-P7b1K_pp494aPLZ2sFI3Sw.gif-355.2kB

当然,如果直接从磁盘缓存中加载图片的话,Glide 要比 Picasso 快。这要归功于 Glide 的设计。Picasso 在将图片设置到 ImageView 之前,需要在运行时将图片适配压缩到 ImageView 的大小,这会耗费一定的时间,即使我们使用 .noFade() 来取消图片加载时的渐变效果也是如此。

1-0nIGJyOVgut-kCDMbu3kIg.gif-488.3kB

Picasso 和 Glide 的相同特性

文章开头我们说过,Glide 可以看作是 Picasso 的变种,因此我们可以发现,两者在特性和使用方式上有很多共同点,例如图片大小的适配操作:

// Picasso.resize(300, 200);// Glide.override(300, 200);

图片居中裁剪:

// Picasso.centerCrop();// Glide.centerCrop();

图片的变换:

// Picasso.transform(new CircleTransform())// Glide.transform(new CircleTransform(context))

给 ImageView 设置默认图片和出错时显示的图片:

// Picasso.placeholder(R.drawable.placeholder).error(R.drawable.imagenotfound)// Glide.placeholder(R.drawable.placeholder).error(R.drawable.imagenotfound)

可以看到,如果你之前使用过 Picasso,那么想移植代码到 Glide 是非常容易的。

Glide 独有的特性

  • 对 GIF 动画的支持:Glide 能很好的支持 GIF 动画,加载 GIF 图很简单,直接使用Glide.with(...).load(...) 即可。而且,由于 Glide 能够和 Activity 的生命周期协作,GIF 图片在 onStop() 生命周期函数调用时会停止动画,从而减少动画后台电量的耗费。目前 Picasso 是不支持 GIF 动画的,因此,如果你的应用想支持 GIF 动画的显示,那么只能选择 Glide。
  • 缩略图的支持:使用 Glide,你可以在同一时间加载多张图片到同一个 ImageView 中,例如可以首先加载只有 ImageView 十分之一大小的缩略图,然后在上面再加载完整大小的图片。

总结

从上面的分析可以看出,Glide 继承自 Picasso,而且青出于蓝而胜于蓝,相信通过上面的对比大家应该已经有了自己的选择。

原创粉丝点击