转载请注明出处:
http://blog.csdn.net/BruceHurrican/article/details/64917850
现在的 app如果没有图片展示的话,就不能算是完整的 app 了。受限于 android 本身的图片加载机制,如果要从设备本地加载图片或者从网络加载图片,现有的 API编码起来很麻烦,而且性能上面也不是很好。和大多数开发者一样,我当时在做一个项目时,也是从网上搜了下,看看好用的图片加载库都有哪些,然后随便选了一个,就在项目中用了。随着项目的迭代,对图片库的业务扩展越来越多,就要考虑图片库的更换问题了,这时发现,原有图片库和工程代码的耦合性太强了,更换起来太麻烦,说多了都是泪啊。
下面,我就说下,在图片库替换时,我做的一些考虑吧。如标题所述,是从 APK瘦身的角度来比较图片库的,本篇文章没有涉及到网络图片请求响应时长比较,内存开销比较等问题,仅从库的大小、方法数、易用性、代码侵入性等方面来探讨各个图片库的差异。
现在市场上可以说90%以上 app 都会用到下面的图片库,有的 app 可能使用的库还不止一个。
为了方便描述,下文中的部分名词作简写处理:
- DMC dex-method-counts
- UIL UIL universal-image-loader
jar 包大小(kb) | classyshark方法数 | dex-methods-count方法数 | 是否支持加载 gif 动图 | 显示控件 | 是否原生支持圆角图片 | |
---|---|---|---|---|---|---|
Glide | 475 | 2288 | 2365 | 是 | ImageView | 否 |
volley | 86 | 345 | 362+19 | 否 | NetWorkImageView | 否 |
cube | 272 | 1586 | 1720 | 否 | CubeImageView | 是 |
UIL | 162 | 867 | 878 | 否 | ImageView | 是 |
Picasso | 120 | 508 | 536 | 否 | ImageView | 否 |
Fresco | 859 | 4317 | 4535 | 是 | SimpleDraweeView | 是 |
classyshark 是 google 开发并维护的一个统计 apk,jar 中方法数的工具,拥有 GUI界面,具备跨平台特性。classyshark 统计到的方法数中并不包括引用的方法数如使用到的 android.jar 系统包中的方法数。
DMC = classyshark 方法数 + 引用系统包中的方法数。
关于统计apk 方法数,可以看我另一篇文章统计 apk 方法数和代码行数小工具
在 Android Studio 2.2+ 版本中分析 apk 功能,操作路径: Build - Analyze APK - classes.dex 显示的 信息 “This dex file defines 3372 classes with 23938 methods, and references 29709 methods”。此处的 23938 methods,29709 methods 分别对应 chassyshark 统计方法数 和 DMC 统计方法数。
glide
google 开发并维护的一款图片加载库,以3.7.0版本为例,链式调用,支持加载 gif 动图,承载图片控件可以是原生控件 ImageView,加载图片的网络请求生命周期和入参 Glide.with(context) 输入的 context 生命周期绑定,如果输入的是 Activity、Fragment、Application context 则该图片网络请求的生命周期绑定 Activity、Fragment、Application context。可以设置加载过程中多种状态资源,如加载中、加载开始、加载失败。在 glide 原有 API 是没有直接方法设置加载圆角图片的,但是可以通过 transform 方法输入自定义的 BitmapTransformation 来实现圆角图片。Glide 的实例采用的是 DCL。支持对加载的 gif 动图进行裁剪,如圆角化处理。目前该库的维护上在持续更新。
volley
google 开发并维护,加载图片的方式可以使用 ImageRequest,ImageLoader,NetworkImageView,如果使用 NetWorkImageView 需要对 volley 库进行瘦身,有一定的工作量,同时,使用 NetWorkImageView 对布局文件具有一定的侵入性,不利于后期图片库的更换。NetWorkImageView 支持加载网络图片过程中的状态显示,API 不支持直接设置圆角图片。为了防止 ML,现在通行的做法是,整个网络请求的生命周期绑定 Application context。针对当个页面的图片加载需要考虑其请求的生命周期问题。目前该库仍在持续更新。
cube
阿里一淘出品,是基于 ImageLoader 的二次封装,内部图片的加载方式和 ImageLoader 一致,和 NetWorkImageView 一样对布局文件有一定的侵入性,不利于后期扩展维护,在加载本地资源时使用 setImageResource 没有效果。核心类 Cube 生命周期同 Application, 应对并发访问会造成过多的内存开销,如同时创建两份实例。方便使用圆角图片。该库目前已经停止更新,最新版本为1.0.44。
universal-image-loader
老牌图片加载框架,UIL支持加载图片过程中多种状态回调和资源显示。核心类 ImageLoader 采用 DCL 方式保证多线程并发条件下的类型安全。方便使用圆角图片。支持多种 URI 资源的加载,以下是官网介绍
“http://site.com/image.png” // from Web
“file:///mnt/sdcard/image.png” // from SD card
“file:///mnt/sdcard/video.mp4” // from SD card (video thumbnail)
“content://media/external/images/media/13” // from content provider
“content://media/external/video/media/13” // from content provider (video thumbnail)
“assets://image.png” // from assets
“drawable://” + R.drawable.img // from drawables (non-9patch images)
目前该库最近一版更新于一年前。
Picasso
square 出品,核心类 Picasso 采用 DCL,和 glide 一样采用链式调用。生命周期绑定的是 application context, 不论入参是何种类型的 context 都会转换成 application context。加载图片过程中,只能监听到加载失败时的信息,其他的状态,Picasso 没有开放相应 API 给开发者,不利于应用调试。原生 API 并不支持圆角图片,不过可以通过调用 transform 输入自定义的 Transform 来实现圆角图片。目前该库由 square 当家码农 jakeWharton 大神维护更新。
Fresco
FaceBook 开发并维护,提供给开发者的 aar 包有 animated-base,animated-gif,drawee,fbcore,fresco,imagepipeline,imagepipeline-base,功能强大,目前官方已经有良好的中文文档支持。Fresco 初始化绑定的参数是 application context,支持图片加载时的 fade 动画,使用 SimpleDraweeView 加载图片时必须指定宽高或者 match_parent,不支持 wrap_content,支架加载圆角图片。fresco 支持类似于 PS中的图层叠加,不过需要注意的是当使用图层时,资源的重复利用。支持加载过程中的状态显示,通过进度条的方式显示,默认进度条是蓝色的,原生交互上比其他框架上要好,其他框架需要通过自定义 view 的方式实现此功能。fresco 支持图片加载失败时可以重试的功能。支持加载 GIF、webP 图片,但是需要引入相应的依赖包,不支持对 gif 图片的圆角化处理。SimpleDraweeView 对布局文件有一定的代码侵入性。目前该库由 FaceBook 维护更新。
总结
上面只是大致介绍了各个图片库的特点。在项目开发中,如果能够预估到项目在最近1-2年内的业务需要的话,可以选择合适的库。从上面表格中可以看出,Fresco 虽然功能强大,但是方法数,包体积都非常大,NetWorkImageView 所在的 volley 虽然包小方法少,但是使用时需要考虑并发和代码侵入的问题。在图片库选型时,要考虑到当前业务的需要和后期业务发展对库的要求,比如 app 的个人中心界面,当前业务可能只是显示默认图片,下个月的版本就要支持用户自定义的图片了,半年后就要支持 gif 图片了,这时选择时就不能随便选择了,不然后面就有泪流满面地填坑。从我自己的项目经历来说,不论选择何种库,最好是在外面封装一层再去调用。比如,我在项目中使用 Picasso 这个库,对于工程中所有使用到的地方,我不能直接去调用 Picasso 的方法来加载图片,这样做耦合性太高。我可以新建一个 ImgLoader 类将 Picasso加载图片的方法全部放入该类,外部调用统一ImgLoader来调用。这样后期业务需要增加 gif 动图支持考虑换库时,直接在 ImgLoader 中替换相应的 Picasso 行为即可,外部调用不用修改。