一个常用项目的演进,重构和版本更新的历程

一个项目的版本更新的过程总是伴随着技术的演进和代码的重构,只要你在维护你总是会发现有更好的或者说是更合适的控件,框架值得去适用,这个过程可以是几个星期或者是几个月。
在这里我试着去分析一下通用项目更新跌代的维护历程。

常见的UI控件演进:
1. 跟随流行风尚将普通主页改为侧滑主页,玩起来更炫更简单有趣;
2. 用RecyclerView代替ListView,因为RecyclerView具有更强的扩展性,灵活性,以后的不管什么数据展示,瀑布流什么之类,宝宝再也不用大刀阔斧的进行代码重构了。

网络框架的演进:
在最开始决定使用那种网络框架的时候我们做了个货比三家不吃亏,下面我就来对比一下这些常用网络框架的特点和优缺点吧

在看android基础的时候,关于网络操作一般都会介绍HttpClient以及HttpConnection这两个包。前者是apache的开源库,后者是android自带的api。既然提到了他们,都二者进行一个比较,谷歌在官方文档已经说明了,建议在2.3以及以上版本使用 HttpConnection。具体原因呢,是因为对2.1和2.2版本,HttpURLConnection有那么几个Bug,所以建议用Apache 的HTTP Client;之后的版本,建议用HttpURLConnection。Apache的HTTP Client比较强大,拥有庞大而灵活的API,这个实现很稳定,并且Bug很少。然而,也就是因为太庞大了,以至于很难在保证兼容性的情况下改进它,故 android 开发团队不应该维护该库而是转投更为轻量级的httpurlconnection。
当我们开发企业级应用的时候,一般都会选择使用已经封装好的http框架。开源的比较流行的有:
volley
特色 :
Google推出了官方的针对Android平台上的网络通信库volley,能使网络通信更快,更简单,更健壮,Volley在提供了高性能网络通讯功能的同时,对网络图片加载也提供了良好的支持,完全可以满足简单REST客户端的需求, 我们没有理由不跟上时代的潮流。另外,但volley的扩展性很强,可以根据需要定制你自己的网络请求。所以,最后推荐还是使用volley进行开发,当然其他几个库也是非常具有学习以及参考意义的,可以将他们的精髓之处汲取到volley框架的拓展开发之中,做出自己理想的http通讯框架。
简单来说,它提供了如下的便利功能:
JSON,图像等的异步下载;
网络请求的排序(scheduling)
网络请求的优先级处理
缓存
多级别取消请求
和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)
底层的网络请求代码更加清晰,在Volley返回的结果即直接返回了我们需要的Object,同时将统一的错误处理、公共的参数处理和一些公共的返回使用的参数,全部放在我们自定义的Request当中,这样外部请求所需要传入的参数更少,对于错误的处理更加简单,只需要考虑业务需要的Response,其他全局的返回内容则无需进行干扰。通过Volley的引入,帮助我们在业务的开发上变得更加便捷。

缺点:比如大数据(large payloads ),流媒体,这些case,还需要使用原始的方法,比如Download Manager等。

2、OkHttp优点较多
OkHttp是一个现代,快速,高效的Http client,支持HTTP/2以及SPDY,一种开放的网络传输协议,由Google开发,它为你做了很多的事情。

OKHttp是Android版Http客户端。非常高效,支持SPDY、连接池、GZIP和HTTP缓存。

支持SPDY,可以合并多个到同一个主机的请求

OkHttp实现的诸多技术如:连接池,gziping,缓存等就知道网络相关的操作是多么复杂了。

OkHttp扮演着传输层的角色。

OkHttp使用Okio来大大简化数据的访问与存储,Okio是一个增强 java.io 和 java.nio的库。

OkHttp 处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。

OkHttp还处理了代理服务器问题和SSL握手失败问题。

OkHttp是一个Java的HTTP+SPDY客户端开发包,同时也支持Android。需要Android 2.3以上

OKHttp是Android版Http客户端。非常高效,支持SPDY、连接池、GZIP和 HTTP 缓存。

默认情况下,OKHttp会自动处理常见的网络问题,像二次连接、SSL的握手问题。

如果你的应用程序中集成了OKHttp,Retrofit默认会使用OKHttp处理其他网络层请求。

从Android4.4开始HttpURLConnection的底层实现采用的是okHttp

缓存响应避免重复的网络请求

目前,该封装库志支持:

1, 一般的get请求

2,一般的post请求

3,基于Http的文件上传

4, 文件下载

5,上传下载的进度回调

6, 加载图片

7, 支持请求回调,直接返回对象、对象集合

8, 支持session的保持

9, 支持自签名网站https的访问,提供方法设置下证书就行

10, 支持取消某个请求

为什么要做缓存,或者说有什么好处?

减少服务器负荷,降低延迟提升用户体验。

复杂的缓存策略会根据用户当前的网络情况采取不同的缓存策略,比如在2g网络很差的情况下,提高缓存使用的时间;不用的应用、业务需求、接口所需要的缓存策略也会不一样,有的要保证数据的实时性,所以不能有缓存,有的你可以缓存5分钟,等等。你要根据具体情况所需数据的时效性情况给出不同的方案。当然你也可以全部都一样的缓存策略,看你自己。

3. xUtils简介

xUtils 最初源于Afinal框架,进行了大量重构,使得xUtils支持大文件上传,更全面的http请求协议支持(10种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响…
xUitls最低兼容android 2.2 (api level 8)

目前xUtils主要有四大模块:
DbUtils模块:
android中的orm框架,一行代码就可以进行增删改查;
支持事务,默认关闭;
可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名);
支持绑定外键,保存实体时外键关联实体自动保存或更新;
自动加载外键关联实体,支持延时加载;
支持链式表达查询,更直观的查询语义,参考下面的介绍或sample中的例子。
ViewUtils模块:
android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定;
新的事件绑定方式,使用混淆工具混淆后仍可正常工作;
目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。
HttpUtils模块:
支持同步,异步方式的请求;
支持大文件上传,上传大文件不会oom;
支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求;
下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件;
返回文本内容的请求(默认只启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。
BitmapUtils模块:
加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象;
支持加载网络图片和本地图片;
内存管理使用lru算法,更好的管理bitmap内存;
可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等…
使用xUtils快速开发框架需要有以下权限:

<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 

混淆时注意事项:
添加Android默认混淆配置${sdk.dir}/tools/proguard/proguard-android.txt
不要混淆xUtils中的注解类型,添加混淆配置:-keep class * extends java.lang.annotation.Annotation { *; }
对使用DbUtils模块持久化的实体类不要混淆,或者注解所有表和列名称@Table(name=”xxx”),@Id(column=”xxx”),@Column(column=”xxx”),@Foreign(column=”xxx”,foreign=”xxx”);

缺点:代码量大,代码可读性变差,冗余影响程序运行效率

4. Retrofit
Retrofit2.0用了动态代理技术,通过解析注解生成Http请求,把请求交给OkHttp,然后通过我们设置的ConverterFactory进行serialization和deserialization,最后通过CallAdapter把结果进行进一步适配,实现了对Rxjava,Guava和java8的支持。

retrofit使用了builder模式,我们可以在此设置请求的URL,ConverterFactory(此处用了Gson解析,当然你也可以自定义数据解析器,只要你的解析器继承 Converter.Factory就行),或者设置回调时的适配器。在retrofit中提供了三种CallAdapterFactory:GuavaCallAdapterFactory,Java8CallAdapterFactory和RxJavaCallAdapterFactory。

图片加载框架的演进

是以图片加文字为主体的内容,因此会有大量的图片显示需求。和网络框架选型类似,早期选择了比较熟悉的UIL来做图片加载,可以同时支持本地图片和网络图片的加载,在当时可以满足我们的基本需求。
我们开始使用更加高清的图片,随之加载速度变慢,占用更多的内存,而且这个时候UIL的作者基本很少维护。我们开始调研使用新的图片加载框架。此时Fresco刚刚出来,还不太稳定,当时没敢用。给我们的可选项有Picasso和Glide两个可选项,Picasso比较轻量,但是相比于UIL在性能上没有太好的提高。Glide代码量较大,不过它会在本地保存多份缓存(原始图片和实际显示尺寸的图片),这样加载本地缓存的时候,可以直接显示大小刚好的尺寸,减少解码的时间,因此会比UIL要快很多。
后来我们需要支持gif的动画显示,而Glide对动画的兼容性又不是特别好,这个时候我们直接切到了Fresco。同时Fresco对webp的良好支持,使得我们在后期切换到webp格式的时候,减少了很多工作量。Fresco在4.4及以下版本使用匿名内存来作为内存缓存,为我们减少OOM做了巨大的贡献。
我们使用的这几个图片加载框架,每个框架的使用都有非常大的区别,这就导致迁移的时候工作量巨大。为了降低迁移成本,我们封装了自己的ImageLoader,在ImageLoader中来实现具体的图片加载,这样保证在迁移的时候,最大程度的降低代码的改动(不过在迁移到Fresco的时候还是改动巨大,因为我们不能直接使用ImageView了o(︶︿︶)o。

推送的升级
推送,我觉得也有必要说一说。最初我们快速选用了百度云推送,在当时看来百度的推送比较稳定,同时接入比较简单。实际使用了一年之后,发现送达率不是特别高,并且数据统计做的不太好,无法比较好的统计推送效果。在调研之后,我们决定迁移到小米推送+友盟推送的模式,针对小米用户开启小米推送,其他用户采用友盟推送,为了平滑过渡,在切换期间同时向未升级的老用户继续使用百度云推送进行推送。

架构升级
一般项目中由于一直以来在业务开发占用的时间比较多,目前App的整体架构没有做过太大的改变。
在Adapter的使用方面,我们将ListView或RecyclerView的Item放到单独的ItemHander,这样可以在不同的页面可以通过将不同的Item组装到一起,从而满足不同地方的需求。这样可以在ListView或RecyclerView来复用相同的代码,提高代码的可维护性。
前面网络层说到我们的错误处理,这个也是做过比较大的升级。最初时候,网络错误、http请求错误、后台和客户端的错误,都分别在不同的层级进行处理。目前我们在发生错误的时候将错误全部以Exception的方式抛出,最后在上层进行错误的处理。
App中的状态同步,早期使用使用数据库缓存部分数据,或者使用LocalBroadcast进行广播通讯,前者有很多的限制,后者使用起来较为复杂。近期我们改用EventBus进行状态同步,同时这样也使得各个页面之间的耦合也低。
App中占比很大的部分是从网络请求数据,获得数据后进行展示,还是以MVC为主。在一些模块的部分地方,做一些databinding,MVP等的测试。后面有机会会更多大范围的重构。

APK最初大约只有5M,历史最高峰达到了23M,在App减肥上我们也做了一些努力,主要是使用tinypng压缩图片,so只保留arm的支持.

现在持续集成还是蛮火的,自然我们也在用。最初的时候,我们每天需要手动打包,打完包之后打开fir的网站,将apk传上去,然后在公司的微信群吼一声,告诉大家我们发包了。经历一段时间后,我们编写了一个Gradle插件帮助我们自动上传到fir,在之后我们搭建了Jenkins自动完成这一系列步骤,并通过邮件告知大家;

你可能感兴趣的:(重难点摘要,重构,阅读,框架,项目演进)