1. Android开发框架的选择
我们知道原生Android开发已经是一个基础的MVC框架,其中xml部分被认为是View层,Activity层是Control层,所以在项目刚开始开发的时候并没有遇到太多问题。
但是在实际项目中,Activiy层除了做C层的工作以外,还会有承担部分View层的工作,这样导致了很容易出现一个Activity的超级类,维护起来十分复杂。目前我们自己的项目比这个情况更糟糕,Activity一个类直接写了所有的业务逻辑,导致这个类错综复杂,没有任何层级划分,代码阅读和修改都十分的困难。
需要解决这些问题,需要做2个维度的解耦工作
1.分层
2.模块化
两种的方式最终目的是一样的,只不过一个是纵向层面上的解耦,一种是横向层面上的解耦。
目前android主流架构中MVC已经不太适用了,比较流行的是MVP和MVVM,但是MVVM需要用到谷歌的databinding,而目前这部分技术不太成熟,有许多问题。而MVP的架构已经足以满足我们的需求和后续扩展了,所以选用MVP架构。
2.分层架构MVP和模块化的实现
MVP实际上是在MVC的基础上实现的,在android端具体思路就是将activity层作为一个view层剥离出来,Presenter层作为中间层,主要做的是一些逻辑上的处理和消息的传递,Model用来存储数据。
这是一个比较典型的MVP架构的结构图,用户事件由View层响应,然后通过presenter进行消息传递,最后从model层获取数据,再从presenter层返回给view层做数据刷新。
具体如何实现呢,下面将用代码直接说明:
通过包结构,我们可以看一个MVP结构的大致划分,主要有接口有。
View层接口:ICreditView
主要是一些进行UI刷新和状态的处理。
View层的具体实现
Activity里面包含了2个类,一个是View层的对外接口ICreditView,一个是P层的CreditPresenter。
从上面的所有代码可以看到,View层将自己的接口ICreditView交给了Presenter, 而Presenter层持有Model层的也只是一个接口。通过Presenter层将业务层与展现层隔离了开来,这样的好处是什么?
我们知道接口的一个作用通常是用来抽象行为,对外部屏蔽实现细节。所以对于View层来说,业务细节被屏蔽了,对业务层来说,展示细节被屏蔽了。而对于处于中间的Presenter层来说,它就像一个接口拼装器,把View层发出的请求传递给业务层,把业务层返回的数据又送还给View层展示,至于前后两端怎么实现的,它才不用关心。
接口的第二个作用是可以用来切换实现。我们先看下面的代码。
Model层接口:ICreditDataSource
主要是一些数据存储和数据提取的处理。
我们可以通过实现这个类来实现一些我们需要的model数据
这里的数据都是本地的,获取和存储都没有任何问题,但是在我们实际工作中,很多数据是从我们的服务端获取的,这在做需求的时候就会有个问题。服务端的同学还没来得及做好相关的接口,我们可以直接自己定义一个Test的Model实现类,这样就可以先做好逻辑和界面,等服务端做好后,再直接进行联调,就OK了。
类似的应用场景其实有非常非常多,这里我们就看到了使用接口解耦的一个好处了,不仅把业务层和展示层解耦开来,还把Android开发同其它的一切的外部数据依赖都解耦开来。
到现在为止一个基于MVP简单框架就搭建完成了,但其实还遗留了一个比较大的问题。
我们从Model层获取数据,大部分都会是一个耗时操作,而android又规定主线程不能做耗时操作和网络请求,否则会出现ANR甚至直接报错。
正常情况下,我们想要做耗时操作,都会启动一个线程,然后完成后做一次线程切换,回到主线程做处理,按照android给我们的一些方式,可以用Handler,用可以用runOnUiThread,例如这样:
这里其实看起来还算OK,但是存在2个隐患。
1、多次调用这个方法,会多次启动线程,造成不必要的资源浪费
2、如果线程多次切换,这样写就会有非常多的嵌套,十分影响代码体验。
好在有了RxJava ,可以比较方便的解决这个问题。
3. 使用RxJava来进行线程控制
RxJava是一个天生的做异步的工具,他的详细介绍可以去看扔物线大神的这篇介绍,写的非常详细,很适合初次学习RxJava的同学去看。
http://gank.io/post/560e15be2dca930e00da1083
还是回到刚才的那段线程切换的代码,如果我们需要用RxJava做要怎么做呢?
简单解释下,mDataSource就是我们的Model层,Schedulers.io是RxJava提供的IO管理线程,这样就解决了我们之前的第一个问题,线程被反复调起浪费资源的问题。同时AndroidSchedulers.mainThread是android线程,我们可以反复在他们之间切换,这样按照RxJava的书写规范,完全就可以避免多层嵌套的问题。
当然RxJava的使用场景远远不止这些。下面列出了一些常见的RxJava的常用场景,其实还有更多的其它功能等待着大家去挖掘。
1、取数据先检查缓存的场景
2、需要等到多个接口并发取完数据,再更新
3、一个接口的请求依赖另一个API请求返回的数据
4、界面按钮需要防止连续点击的情况
5、响应式的界面
6、复杂的数据变换
4、Retrofit的使用
Retrofit是一个基于okHttp的网络框架,他的优点在于基于注解的接口式编程,不用写具体的实现,这样更进一步的解耦了Presenter层和Model层。但是需要使用到这个框架,有一些前提条件,就是服务端必需支持REST风格。我们自己的服务端接口目前并没有对这方面进行支持,但是调用第三方的接口中,Face++对REST进行了支持,而且老的接口使用的是asyn-http,这个是一个基于httpClient的框架,谷歌在6.0以后放弃了对这部分的支持,所以这次重构也对这部分代码做了一次重构。
具体的retrofit的使用可以网上搜到,有很多相关的教程,这次算是一次项目中的实践,可惜的是我们的服务端目前没有时间做出对REST的支持,后续如果支持到,会更多的研究里面很多的细节性问题了。