一、目录
二、前言
面试官:你们项目中加载图片都是用的什么框架?
面试者:Glide啊(内心窃喜)
面试官:为什么使用Glide而不用其他的?
面试者:(沉默10s),Glide好啊,我比较喜欢。(内心不安)
面试官:……(能不能好好聊天了)
这篇博文主要就是针对平常使用到的框架做一个整理和分析其优劣。
为了从整体上进行把握,先来看看一个完整的APP整体架构
三、APP的整体架构
一个理想的APP架构,应该拥有如下特点
基于以上设计原则,我们可以看出APP架构图,最上层是应用层,应用层以下都属于基础框架层,基础框架层包括:组件层、基础层和跨平台层。
四、技术选型的考量点
五、日志记录能力
Logger(https://github.com/orhanobut/logger) 是基于系统Log类基础上进行的封装,但新增了如下超赞的特性。
Logcat截图
再者,Logger只支持输出日志到Logcat,但项目开发中往往还存在将日志保存到磁盘上的需求,如何将两者结合起来呢?这是可用timber(https://github.com/JakeWharton/timber) 。
timber是JakeWharton开源的一个日志记录库,它的特点是可扩展的框架,开发者可以方便快捷的集成不同类型的日志记录方式,例如,打印日志到Logcat、打印日志到文件、打印日志到网络等,timber通过一行代码就可以同时调用多种方式。
timber的思想很简单,就是维护一个森林对象,它由不同类型的日志树组合而成,例如,Logcat记录树、文件记录树、网络记录树等,森林对象提供对外的接口进行日志打印。每种类型的树都可以通过种植操作把自己添加到森林对象中,或者通过移除操作从森林对象中删除,从而实现该类型日志记录的开启和关闭。
最终我们的日志记录模块将由timber+Logger+LogUtils组成,当然轮子找到了,轮子的兼容合并就得靠我们自己实现了,同时我们还得增加打印到文件的日志树和打印到网络的日志树实现。
六、JSON解析能力
gson
gosn是Google出品的JSON解析函数库,可以将JSON字符串反序列化对应的Java对象,或者反过来将Java对象序列化为对应的JSON字符串,免去了开发者手动通过JSONObject和JSONArray将JSON字段逐个进行解析的烦恼,也减少了出错的可能性,增强了代码的质量。使用gson解析时,对应的Java实体类无需使用注解进行标记,支持任意复杂Java对象包括没有源代码的对象。
jackson
jcakson是Java语言的一个流行的JSON函数库,在Android开发中使用时,主要包含三部分。
由于jackson是针对Java语言通用的JSON函数库,并没有为Android优化定制过,因此函数保重包含很多非必要的API,相比其他的JSON函数库,用于Android平台会更显著的增大最终生成的APK的体积。
Fastjson是阿里巴巴出品的一个Java语言编写的高性能且功能完善的JSON函数库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,号称是目前Java语言中最快的JSON库。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。
由于是Java语言通用的,因此,以前在Android上使用时,Fastjson不可避免的引入了很多对于Android而言冗余的功能,从而增加了包大小,很多人使用的就是标准版的fastjson,但事实上,fastjson还存在一个专门为Android定制的版本—fastjson.android 。和标准版本相比,Android版本去掉了一些Android虚拟机dalvik不支持的功能,使得jar更小。
LoganSquare
LoganSquare是近两年崛起的快速解析和序列化JSON的Android函数库,其底层基于jackson的streaming API,使用APT(Android Annotation Tool)实现编译时注解,从而提高JSON解析和序列化的性能。官网上可以看到LoganSquare和gson、jackson databind的性能对比。
再来看下jar包的大小
从性能和包大小综合考虑,最终我们会选择Fastjson.android作为基础技术堆栈中的JSON解析和序列化库。
七、数据库操作能力
ActiveAndroid是一种Active Record风格的ORM框架,Active Record(活动目录)是Yii,Rails等框架中对ORM实现的典型命名方式。它极大的简化数据库的使用,使用面向对象的方式管理数据库,告别手写SQL的历史。每一个数据库表都可以被映射为一个类,开发者只需使用类似save()或者delete()这样的函数即可。
不过ActiveAndroid已经基本上处于维护阶段了,最新的一个Release版本是在2012年发布的。
ormlite
ormlite是Java平台的一个ORM框架,支持JDBC连接、Spring和Android平台。在Android中使用时,它包含两部分。
与ActiveAndroid类似,ormlite也已经不是一个活跃的开源库,最近一次Release版本是在2013年发布的。
greenDAO
greenDAO是一个轻量级且快速的ORM框架,专门为Android高度优化和定制,它能够支持每秒数千条记录的CRUD操作。官网上给出一张性能对比图
Realm是一个全新的移动数据库引擎,它既不是基于iOS平台的Core Data,也不是基于SQLite,它拥有自己的数据库存储引擎,并实现了高效快速的数据库构建操作,相比Core Data和SQLite,Realm操作要快很多,跟ORM框架相比就更不用说了。
Realm的好处如下:
我们看下上述四种数据库包大小。
可以看出,前三个还是正常范围,但Realm的大小一般项目可能无法接受。这是因为不同CPU架构平台的 .so 文件增加了整个包的大小,由于arm平台的so在其他平台上面能够以兼容模式运行的,虽然会损失性能,但是可以极大地减少函数库占用的空间。因此,可以选择只保留armeabi-v7a和x86两个平台的 .so 文件,直接删除无用的 .so 文件,或者通过工程的build.gradle文件中增加 ndk abi 过滤,语句如下:
八、网络通信能力
Android最经典的网络异步通信函数库,它对Apache的HttpClient API的封装使得开发者可以简洁优雅地实现网络请求和响应,并且同时支持同步和异步请求。主要特性如下:
但是在6.0之后,系统对开发者隐藏了HttpClient函数库,这显著增大了使用android-async-http的代价。 如果铁了心想继续使用HttpClient,官方推荐的做法是在编译期引入org.apache.http.legacy 这个库,库目录在Android SDK目录下的platforms\android-23\optional中找到,它的作用是确保在编译时不会出现找不到HttpClient相关API的错误,在应用运行时可以不依赖这个库,因为6.0以上的Android系统还没有真正移除HttpClient的代码,只不过API设置为对开发者不可见。我们查看android-async-http源码发现,需要使用下面这个函数库来替换之前的Apache的HttpClient。
OkHttp是一个高效的HTTP客户端,具有如下特性。
OkHttp在网络性能很差的情况下能够很好地工作,它能够避免常见的网络连接问题。如果你的HTTP服务有多个IP地址,OkHttp在第一次连接失败是,会尝试其他可选的地址。这对于IPv4+IPv6以及托管在冗余数据中心的服务来说是必要的。OkHttp使用现代的TLS特性(SNI,ALPN)初始化HTTP连接,当握手失败时,会降低使用TSL1.0初始化连接。
OkHttp依赖于okio,okio作为java.io和java.nio的补充,是square公司开发的一个函数库。okio使得开发者可以更好地访问、存储和处理数据。一开始是作为OkHttp的一个组件存在的,当然我们也可以单独使用它。
使用Okhttp需要引入Jar包,包的大小为:
326+66 = 392KB
Volley是Google在2013年发布的用于Android平台的网络通信库,能使网络通信更快、更简单、更健壮。Volley特别使用于数据量小等通信频繁的场景。
Volley是为了简化网络任务而设计的,用于帮助开发者处理请求、加载、缓存、多线程、同步等任务。Volley设计了一个灵活的网络栈适配器,在Android2.2及之前的版本中,Volley底层使用Apache HttpClient,在Android2.3及以上版本中,它使用HttpURLConnection来发起网络请求,而且开发者也很容易将网络栈切换成使用OkHttp。
确切的说,Retrofit并不是一个完整的网络请求函数库,而是将REST API转换成Java接口的一个开源函数库,它要求服务器API接口遵循REST规范。基于注解使得代码变得很简洁,Retrofit默认情况下使用GSON作为JSON解析器,使用OkHttp实现网络请求,三者通常配合使用,当然我们也可以将这两者换成其他的函数库。
通过以上分析,HttpURLConnection、Apache HttpClient 和OkHttp封装了底层的网络请求,而android-async-http,Volley和Retrofit是基于前面三者的基础上二次开发而成。
最后看下函数库的大小
九、网络通信能力
BitmapFun函数库是Android官方教程中的一个图片加载和缓存实例,对于简单的图片加载需求来说,使用BitmapFun就够了,在早期用的多,现在渐渐退出了实际项目开发的舞台。
Picasso
Picasso是著名的square公司众多开源项目中的一个,它除了实现图片的下载和二级缓存功能,还解决了常见的一些问题。
Glide
Glide是Google推荐的用于Android平台上的图片加载和缓存函数库。这个库被广泛应用在Google的开源项目中,Glide和Picasso有90%的相似度,只是在细节上还是存在不少区别。Glide为包含图片的滚动列表做了尽可能流畅的优化。除了静态图片,Glide也支持GIF格式图片的显示。Glide提供了灵活的API可以让开发者方便地替换下载图片所用的网络函数库,默认情况下,它使用HttpUrlConnection作为网络请求模块,开发者也可以根据自己项目的实际需求灵活使用Google的Volley或者Square的OkHttp等函数库进行替换。
Fresco
Fresco是Facebook开源的功能强大的图片加载和缓存函数库,相比其他图片缓存库,Fresco最显著的特点是具有三级缓存:两级内存缓存和一级磁盘缓存。主要特性如下:
Android-Universal-Image-Loader简称UIL,是Android平台老牌的图片下载和缓存函数库,功能强大灵活且高度可自定义,它提供一系列配置选项,并能很好地控制图片加载和缓存的过程。使用者甚多,现在项目仍在使用。UIL也支持二级缓存,特性如下:
最后看下几个库的包大小
图片函数库的选择需要根据APP的具体情况而定,对于严重依赖图片缓存的APP,例如壁纸类,图片社交类APP来说,可以选择最专业的Fresco。对于一般的APP,选择Fresco会显得比较重,毕竟Fresco 3.4MB的体量摆在这。
根据APP对图片显示和缓存的需求从低到高我们可以对以上函数库做一个排序
BitmapFun < Picasso < Android-Universal-Image-Loader < Glide < Fresco
值得一提的是,如果你的APP计划使用React Native进行部分模块功能的开发的话,那么在基础函数库选择方面需要考虑和React Native的依赖库的复用,这样可以减少引入React Native 所增加的APP的大小,可以复用的函数库有:OkHttp,Fresco,jackson-core.