一、 基础架构
1. 简述
在项目开发中,功能实现往往不是最难的,最难的是如何让项目始终保持良好的扩展性、可维护性!如果一个项目中,各个模块的耦合性很高,各个类的职责不清晰明了,类之间的依赖关系混乱,代码臃肿不堪,业务扩展变得困难,甚至会出现牵一发而动全身,那么重构就应该提上日程。
2. 常用模型mvc与mvp
在Android开发中,目前用得比较多的是mvc模型与mvp模型,以下简单介绍:
1)、mvc模型
model:Model对应于本地文件或网络获取的数据体,很多情况下数据体的处理也放在Model层处理;
View:在Android中,View层对应的是界面的控件,一般为xml布局文件或者自定义View;
Controller:在Android中,Controller层由Activity、Fragment承当。一般情况下,会在Activity、Fragment中获取数据以及界面元素,并将两者进行绑定。
优缺点:
优点:理解起来比较容易,技术含量并不高,对开发和维护来说成本都比较低也易于维护和修改,其次是耦合性不高,表现层与业务层分离各司其职,对开发有利。
缺点:没有明确定义,完全理解MVC模式并不是很容易,需要精心设计,需要花费一定时间去思考。
2)、mvp模型:
Presenter:交互中间人,连接View和Model的纽带,从Model层获取到数据后,返回给View层,使得View和Model之间没有耦合,也将业务逻辑从View角色上抽离出来。
View:对应Activity、Fragment或者某个View控件,持有一个Presenter成员变量。通常View需要实现实现一个逻辑接口,将View上的操作转交给Presenter进行实现,最后,Presenter调用View逻辑接口将结果返回给View元素。
Model:Model层主要提供数据的存取功能;Presenter需要通过Model层存储,获取数据;无论是本地缓存SharedPreferences、数据库SQlite还是网络。
优缺点:
优点:MVP能够有效地降低View的复杂性,避免业务逻辑被塞进View中,使得View变成一个混乱的大泥坑。MVP模式会解除View与Model之间的耦合,单元测试更加方便。MVP在Android开发中越来越重要了!
缺点:没有明确定义,完全理解MVP模式并不是很容易,需要精心设计,需要花费一定时间去思考
综合各方面因素考虑(第一版代码风格、时间成本、重构风险、团队磨合度),本次重构采用mvc模型!
3. UML类图关系
在Android中,Activity、Fragment主要用于获取数据、界面元素,并将其两者绑定。这也是最容易出现代码臃肿的地方,缺乏经验的开发人员总是喜欢把所有的业务逻辑堆砌到Activity、Fragment中(controller层),造成了Activity,Fragment类的臃肿不堪,阅读性差,维护性差,职责不清晰(违反了面向对象的原则:单一职责),所以重点抽取这两个类。
模板设计模式:定义一个算法所需的框架,而将一些步骤延迟到子类中,使得子类可以不改变这个算法的结构即可重定义该算法的某些特定步骤。
UML类图如下:
根据模板设计模式抽取Activity,UML类图如下:
根据模板设计模式抽取Fragment,UML类图如下:
4. 使用说明
页面可以归纳为两种:1、不带下拉刷新的普通页面;2、带下拉刷新的页面;
BaseActivity、BaseFragment:不带下拉刷新的页面(Activity、Fragment)继承这两个类其中一个;并实现相关抽象方法;
BasePtrListActivity
二、技术选型
1. 简述
在移动端开发中网络请求操作是最繁琐,也是不可避免的,而往往选择一个好的网络请求框架和图片加载框架能让开发事半功倍,如虎添翼,对于网络请求和图片加载框架的选择往往要从各个方面去综合考虑,比如:稳定性,健壮性,对公司项目的适用,以及使用简易程度,对网络请求多样化考虑,以及各个功能模块的特点.然而其他一些框架比如UI框架都是可以很好的应用,可以让应用的稳定性,健壮性都大大提高. 所以针对我们公司,对于网络请求框架,和图片加载框架,及Ui框架提供一些建设性的可行的方案;使用Rxjava+Retrofit2.0+Okhttp3,图片加载使用Glide,因为Android6.0以后Android选择了OkHttp作为底层的网络请求,而Retrofit则是Okhttp的封装,使它更加灵活更易于扩展,可以轻松地与例如RxJava这样优秀的库配合使用。所以,真没什么好犹豫的
网络请求框架
旧版本:
Xutils
虽然是一个很好的开源库,各种封装的都很好,包含DbUtils模块,ViewUtils模块,HttpUtils模块,BitmapUtils模块,但是其实在软件设计领域有一个原则叫做 「单一职责原则」,跟我所说的「专注」不谋而合,一个库能把一件事做好就很不错了。现如今有很多大而全的库,比如这个库可以网络请求,同时又可以图片加载,又可以数据存储,又可以 View 注解等等,我们使用这种库当然方便了,但是你有没有想过?这样会使得你整个项目对它依赖性太强,万一以后这个库不维护了,或者中间某个模块出问题了,这个影响非常大,而且我一直认为大而全的框架可能某一块都做的不够好,所以我在选择的时候更喜欢专注某一领域的框架。
重构后的使用:
Rxjava+Retrofit2.0+Okhttp3:
Retrofit 2.0+Okhttp3支持更加复杂的请求方式和文件的上传和下载以及对cooke,缓存策略的管理,网络日志管理,配合上Rxjava链式编程和线程间的调度,让代码更加简单明了和阅读性,轻松编程,大大提高工作效率,也是目前安卓上最流行的HTTP Client库之一.
Retrofit官方地址:
Retrofit 2.0: The biggest update yet on the best HTTP Client Library for Android
Retrofit官方文档:
http://square.github.io/retrofit/
1. Retrofit的简介:
retrofit是由square公司开发的。square在github上发布了很多优秀的Android开源项目,retrofit 是一个类型安全的 REST 客户端,用于 Android 平台.
就如它网站上的介绍“Retrofit将你的REST API变为Java接口”一样,Retrofit把REST API返回的数据转化为Java对象方便操作,对于在项目中组织API调用,是一个不错的解决方案.
因为其简单与出色的性能,Retrofit 是安卓上最流行的HTTP Client库之一。
随着Google对HttpClient 摒弃,和Volley的逐渐没落,OkHttp开始异军突起,而Retrofit则对okHttp进行了强制依赖。
Retrofit是由Square公司出品的针对于Android和Java的类型安全的Http客户端,
如果看源码会发现其实质上就是对okHttp的封装,使用面向接口的方式进行网络请求,利用动态生成的代理类封装了网络接口请求的底层,
其将请求返回javaBean,对网络认证 REST API进行了很好对支持此,使用Retrofit将会极大的提高我们应用的网络体验。
REST
REST(REpresentational State Transfer)是一组架构约束条件和原则。
RESTful架构都满足以下规则:
-
(1)每一个URI代表一种资源;
-
(2)客户端和服务器之间,传递这种资源的某种表现层;
-
(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现”表现层状态转化”。
Retrofit的特点:
-
Retrofit和Java领域的ORM概念类似, ORM把结构化数据转换为Java对象,而Retrofit 把REST API返回的数据转化为Java对象方便操作。同时还封装了网络代码的调用。
-
使用的是retrofit2.0注解的方式简化代码,也支持各种的请求方式,以及各种类型的参数
方法注解,包含@GET、@POST、@PUT、@DELETE、@PATH、@HEAD、@OPTIONS、@HTTP。
标记注解,包含@FormUrlEncoded、@Multipart、@Streaming。
参数注解,包含@Query,@QueryMap、@Body、@Field,@FieldMap、@Part,@PartMap。
其他注解,@Path、@Header,@Headers、@Url
-
取消正在进行中的业务
service 的模式变成Call的形式的原因是为了让正在进行的事务可以被取消。要做到这点,你只需调用call.cancel()。
-
新的Service定义方式,不再有同步和异步之分
而创建service 的方法也变得和OkHttp的模式一模一样。如果要调用同步请求,只需调用execute;而发起一个异步请求则是调用enqueue。 同步请求 // Synchronous Call in Retrofit 2.0 Call<Repo> call = service.loadRepo(); Repo repo = call.execute(); 以上的代码会阻塞线程,因此你不能在安卓的主线程中调用,不然会面临NetworkOnMainThreadException。如果你想调用execute方法,请在后台线程执行。 异步请求 // Synchronous Call in Retrofit 2.0 Call<Repo> call = service.loadRepo(); call.enqueue(new Callback<Repo>() { @Override public void onResponse(Response<Repo> response) { // Get result Repo from response.body() } @Override public void onFailure(Throwable t) { } }); 以上代码发起了一个在后台线程的请求并从response 的response.body()方法中获取一个结果对象。注意这里的onResponse和onFailure方法是在主线程中调用的。 我建议你使用enqueue,它最符合 Android OS的习惯。
-
自定义Gson对象
为了以防你需要调整json里面的一些格式,比如,Date Format。你可以创建一个Gson 对象并把它传递给GsonConverterFactory.create()。 Gson gson = new GsonBuilder() .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") .create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://api.nuuneoi.com/base/") .addConverterFactory(GsonConverterFactory.create(gson)) .build(); service = retrofit.create(APIService.class);
-
新的URL定义方式
Base URL与@Url 不是简单的组合在一起而是和<a href="...">的处理方式一致
-
配合okhttp3使用可以快速的设置请求相关的设置
-
配合Gson使用可以快速的把json的数据解析成javabean对象
2. Okhttp3的简介:
Retrofit只是对okhttp的高度封装和优化,但是实际的请求还是在okhttp中完成的, 所以我们选择了 retrofit2.0+okhttp3的方式
官方介绍
github源码
使用范围
OkHttp支持Android 2.3及其以上版本。 对于Java, JDK1.7以上。
尽管Google在大部分安卓版本中推荐使用HttpURLConnection,但是这个类相比HttpClient实在是太难用,太弱爆了。
OkHttp是一个相对成熟的解决方案,据说Android4.4的源码中可以看到HttpURLConnection已经替换成OkHttp实现了。所以我们更有理由相信OkHttp的强大。
OkHttp 处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败问题。
使用 OkHttp 无需重写您程序中的网络代码。OkHttp实现了几乎和java.net.HttpURLConnection一样的API。如果你用了 Apache HttpClient,则OkHttp也提供了一个对应的okhttp-apache 模块。
特点:
- Use an Interceptor from OkHttp
可以设置网络拦截器
1,使用网络拦截器设置固定的参数Token以及依他固定参数
2,使用网络拦截器设置缓存策略,在连接网络时缓存时间的设置以及无网络的情况下缓存时间的设置
3,使用网络日志拦截器,可以清晰的看见请求发送的请求头,请求体内容以及返回的数据
-
使用cookejar对cooke进行管理,维持会话的保持和失效,实现了对cooke的自动管理
-
对请求数据的缓存设置,可以具体的设置缓存的大小,以及缓存时间
-
自定义的线程池,轻易的取消网络的请求,以及设置网络请求超时时间,读写超时时间
-
处理验证 相关资料:HTTP AUTH 那些事 - 王绍全的博客 - 博客频道 - CSDN.NET
OkHttp会自动重试未验证的请求。当响应是401 Not Authorized时,Authenticator会被要求提供证书。Authenticator的实现中需要建立一个新的包含证书的请求。如果没有证书可用,返回null来跳过尝试。
public List
challenges() Returns the authorization challenges appropriate for this response's code. If the response code is 401 unauthorized, this returns the "WWW-Authenticate" challenges. If the response code is 407 proxy unauthorized, this returns the "Proxy-Authenticate" challenges. Otherwise this returns an empty list of challenges. -
提取响应头
典型的HTTP头 像是一个 Map<String, String> :每个字段都有一个或没有值。但是一些头允许多个值,像Guava的Multimap。例如:HTTP响应里面提供的Vary响应头,就是多值的。OkHttp的api试图让这些情况都适用。 当写请求头的时候,使用header(name, value)可以设置唯一的name、value。如果已经有值,旧的将被移除,然后添加新的。使用addHeader(name, value)可以添加多值(添加,不移除已有的)。 当读取响应头时,使用header(name)返回最后出现的name、value。通常情况这也是唯一的name、value。如果没有值,那么header(name)将返回null。如果想读取字段对应的所有值,使用headers(name)会返回一个list。 为了获取所有的Header,Headers类支持按index访问。
Rxjava
简介
一个词:异步。
RxJava 在 GitHub 主页上的自我介绍是 “a library for composing asynchronous and event-based programs using observable sequences for the Java VM”(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava ,概括得非常精准。
然而,对于初学者来说,这太难看懂了。因为它是一个『总结』,而初学者更需要一个『引言』。
其实, RxJava 的本质可以压缩为异步这一个词。说到根上,它就是一个实现异步操作的库,而别的定语都是基于这之上的。
API 介绍和原理简析
这个我就做不到一个词说明了……因为这一节的主要内容就是一步步地说明 RxJava 到底怎样做到了异步,怎样做到了简洁。
- 概念:扩展的观察者模式
RxJava 的异步实现,是通过一种扩展的观察者模式来实现的。
观察者模式
观察者模式面向的需求是:A 对象(观察者)对 B 对象(被观察者)的某种变化高度敏感,需要在 B 变化的一瞬间做出反应。举个例子,新闻里喜闻乐见的警察抓小偷,警察需要在小偷伸手作案的时候实施抓捕。在这个例子里,警察是观察者,小偷是被观察者,警察需要时刻盯着小偷的一举一动,才能保证不会漏过任何瞬间。程序的观察者模式和这种真正的『观察』略有不同,观察者不需要时刻盯着被观察者(例如 A 不需要每过 2ms 就检查一次 B 的状态),而是采用注册(Register)或者称为订阅(Subscribe)的方式,告诉被观察者:我需要你的某某状态,你要在它变化的时候通知我。 Android 开发中一个比较典型的例子是点击监听器 OnClickListener 。对设置 OnClickListener 来说, View 是被观察者, OnClickListener 是观察者,二者通过 setOnClickListener() 方法达成订阅关系。订阅之后用户点击按钮的瞬间,Android Framework 就会将点击事件发送给已经注册的 OnClickListener 。采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。当然,这也得益于我们可以随意定制自己程序中的观察者和被观察者,而警察叔叔明显无法要求小偷『你在作案的时候务必通知我』。
RxJava 的观察者模式
RxJava 有四个基本概念:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
与传统观察者模式不同, RxJava 的事件回调方法除了普通事件 onNext() (相当于 onClick() / onEvent())之外,还定义了两个特殊的事件:onCompleted() 和 onError()。
onCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。 onError(): 事件队列异常。在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出。 在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,并且是事件序列中的最后一个。需要注意的是,onCompleted() 和 onError() 二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。
Rxjava的特点:
-
简洁
异步操作很关键的一点是程序的简洁性,因为在调度过程比较复杂的情况下,异步代码经常会既难写也难被读懂。 Android 创造的 AsyncTask 和Handler ,其实都是为了让异步代码更加简洁。RxJava 的优势也是简洁,但它的简洁的与众不同之处在于,随着程序逻辑变得越来越复杂,它依然能够保持简洁。
-
线程控制
除了灵活的变换,RxJava 另一个牛逼的地方,就是线程的自由控制。
-
变换
终于要到牛逼的地方了,不管你激动不激动,反正我是激动了。
RxJava 提供了对事件序列进行变换的支持,这是它的核心功能之一,也是大多数人说『RxJava 真是太好用了』的最大原因。所谓变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列
- RxJava 的适用场景和使用方式
- 与 Retrofit 的结合
Retrofit 是 Square 的一个著名的网络请求库。没有用过 Retrofit 的可以选择跳过这一小节也没关系,我举的每种场景都只是个例子,而且例子之间并无前后关联,只是个抛砖引玉的作用,所以你跳过这里看别的场景也可以的。
- RxBinding
RxBinding 是 Jake Wharton 的一个开源库,它提供了一套在 Android 平台上的基于 RxJava 的 Binding API。所谓 Binding,就是类似设置 OnClickListener 、设置 TextWatcher 这样的注册绑定对象的 API。
- 各种异步操作
前面举的 Retrofit 和 RxBinding 的例子,是两个可以提供现成的 Observable 的库。而如果你有某些异步操作无法用这些库来自动生成 Observable,也完全可以自己写。例如数据库的读写、大图片的载入、文件压缩/解压等各种需要放在后台工作的耗时操作,都可以用 RxJava 来实现
- RxBus
RxBus 名字看起来像一个库,但它并不是一个库,而是一种模式,它的思想是使用 RxJava 来实现了 EventBus ,而让你不再需要使用 Otto 或者 GreenRobot 的 EventBus。至于什么是 RxBus,可以看这篇文章。顺便说一句,Flipboard 已经用 RxBus 替换掉了 Otto ,目前为止没有不良反应。
图片加载框架
旧版本
Picasso
如果你的项目里面,对于图片有一些具体的要求的话,建议使用这个库,但是这个库当你需要对图片作一些具体的操作比如加载圆角矩形图片、裁剪图片为圆形时,需要你自己写一些操作,如果基础不够好的会感觉很困难。还有就是这个库我们只能看到结果,无法关心图片的下载过程
重构后的版本:
Glide:
Glide 是一个高效、开源、 Android设备上的媒体管理框架,它遵循BSD、MIT以及Apache 2.0协议发布。Glide具有获取、解码和展示视频剧照、图片、动画等功能,它还有灵活的API,这些API使开发者能够将Glide应用在几乎任何网络协议栈里。创建Glide的主要目的有两个,一个是实现平滑的图片列表滚动效果,另一个是支持远程图片的获取、大小调整和展示。近日,Glide 3.0发布,现已提供 jar包下载 ,同时还支持使用Gradle以及Maven进行构建。该版本包括很多值得关注的新功能,如支持Gif 动画和视频剧照解码、智能的暂停和重新开始请求、支持缩略图等.
优点:
- 内存开销: 原因在于Picasso是加载了全尺寸的图片到内存,然后让GPU来实时重绘大小。而Glide加载的大小和ImageView的大小是一致的,因此更小
- Image质量的细节
- 磁盘缓存:Picasso和Glide在磁盘缓存策略上有很大的不同。Picasso缓存的是全尺寸的,而Glide缓存的是跟ImageView尺寸相同的
- 同时因为Glide和Activity/Fragment的生命周期是一致的,因此gif的动画也会自动的随着Activity/Fragment的状态暂停、重放。Glide 的缓存在gif这里也是一样,调整大小然后缓存
总结 :
rxjava+retrofit2.0+okhttp3 经过 封装后使用起来比较简单,各方面的应用很适合目前项目,而且很多大公司也在用该模式开发,Retrofit 的封装可以说是很强大,里面涉及到一堆的设计模式,你可以通过注解直接配置请求,你可以使用不同的 http 客户端,虽然默认是用 http ,可以使用不同 Json Converter 来序列化数据,同时提供对 RxJava 的支持,使用 Retrofit + OkHttp + RxJava + Dagger2 可以说是目前比较潮的一套框架,但是需要有比较高的门槛。