注:本篇博文转载于 http://my.oschina.net/mengshuai/blog/541314?fromerr=z8tDxWUH

本文介绍了文章作者从事了几年android应用的开发,经历2次架构变革,第一次集成了RxJava第二次集成了MVP,并将RxJava与MVP完美结合,实现了低耦合,代码简单,测试方便的架构。

其实我们在开发中也遇到过,Android入门门槛较低,如果前期对APP规划不清晰,Coder们对未来变化把握不准,技术架构经验不够强大,最终导致就是一个Activity几千行,里面写了大量的Private方法,拆成几个Fragment、封装出来几个类都是无法解决,结果就是看Activity难受的要死,纠结,看了不爽改也不是不改也不是,严重影响看的人的心情。并且怨天尤人这个是产品人员规划App不好,没有前瞻性,改来改去。。。

这篇文章就是使用新的结构解决该问题。

安卓APP架构

Android Application Architecture

这篇文章主要目的是讲述如何将传统的Activities 与 AsyncTasks 模式向目前主流的MVP架构基础的响应式编程框架过度。

【转载】安卓APP架构-LMLPHP

先畅享一下:~~~如果松耦合架构,分工明确,然后完美的组合在一起工作是一个很吊的事情。
(转个图片还要写明白谁拍的,版权意识真强)

最近几年Android的生态链变化非常迅速,从底层的Android Api到应用层的各种开源的类库、工具更新非常迅速。一不留神就落后了。

我在Ribot团队从事Android应用开发工作三年多,伴随着公司技术的不断创新,积累了很多经验、错误以及在技术选型背后的故事。

旧的应用架构

2012年那个时候,我们的代码都是用的原生Android,没有使用任何的网络请求框架,而是基于AsyncTasks书写。
【转载】安卓APP架构-LMLPHP>The code was structured in two layers: the data layer that was in charge of retrieving/saving data from REST APIs and persistent data stores; and the view layer, whose responsibility was handling and displaying the data on the UI.
The APIProvider provides methods to enable Activities and Fragments to easily interact with the REST API. These methods use URLConnection and AsyncTasks to perform network calls in a separate thread and return the result to the Activities via callbacks.

代码分为两层,Data与View,Data层主要是用来从API获取数据,保存到持久化的db当中。View层主要就是把Data的数据显示到UI上。APIProvider提供方法出来,用于在Activity或者Fragment中方便的进行控制与交互。技术上将,使用URLConnection与AsyncTasks实现了一个异步的网络请求并将结果返回到调用的回调方法里面。

相同的原理CacheProvider提供一系列方法,将SharedPreferences或者SQLite的数据取出来,并且返回给到Activity

问题

主要问题是View层有太多的累赘,以一个博客列表为例来讲述,比如博客需要显示一个ListView,从SQLite读取数据,Activity需要做到以下几点:

  1. 执行APIProvider里面的loadPosts的方法,里面传入回调参数内容。
  2. 等待loadPosts执行成功后,执行回调里面的CacheProvider中的savePosts方法,savePosts也要传入回调参数。
  3. 等待savePosts执行成功后,执行回调里面的方法刷新ListView
  4. 分别书写代码处理2 3 两步的错误回调内容。

这还是一个比较简单的例子,在一些真实的场景中,远程的API可能没有返回程序的必须值,但是activity必须把数据处理完成之后才能显示结果。再一个例子就是如果loadPosts方法需要借助一些其他地方的返回参数时,类似用多线程去实现同步请求,为保证数据正常请求,意味着必须做一个三层的回调,如果再复杂一些,想理清楚这些回调就是很蛋疼的事情。

总之,回调多了之后,Activity与Fragment会乱的要死,并且一般人无法直视。

牛逼的新架构出来了

我们在蛋疼的架构中煎熬了2年,当然也尝试过很多方式,最终也只能是缓和一下乱的问题。我们在APIProvider使用了Volley,代替了AsyncHttpClient,但是其实是一个吊样。

不到2014年我们就开始进行RxJava的预研,然后尝试了一批简单的项目,感觉RxJava的方式是解决我们嵌套回调的终极解决办法。简单的说,RxJava允许你通过异步流的方式管理你的数据,并且还可以通过操作符(Operators)对Observable对象的变换

我们用了几年的经验痛定思痛,搞了下面这么个东西,新的APP的架构图

【转载】安卓APP架构-LMLPHP

与第一种方法相似,这个架构也是分为Data层与View层,Data层包含DataManager与一堆Helper;View层是包含Fragments, Activities, ViewGroups等。

Helper主要是集成第三方的类库,以便于在代码中几行代码就可以清晰的实现某个功能,比如请求API,访问数据库等,虽然不同的应用程序都有不同的类库,但是他们无非就是以下这些内容:

  • 从SharedPreferences中读取或者写入数据
  • 读写SQLite数据库
  • 类似与square的Retrofit服务,也就是Http Client,我们用Restrofit替代了Volley因为他支持Rxjava,并且更吊。

RxJava最核心的两个东西是Observables(被观察者,事件源)和Subscribers(观察者),在Helper类中的Public方法,一般都会返回一个RxJava的Observables;DataManager是整个架构的大脑,他大量的使用Rxjava的operators对Helper返回来的数据进行的整合过滤、二次处理。

下面用一个例子来说明DataManager是做什么的:

  1. 调用Retrofit的服务,去请求一个博客列表的API
  2. 用DatabaseHelper保存这些数据到数据库
  3. 过滤出这些BLOG哪些是今天写的,然后显示到UI界面上。

Observables发出一系列事件,Subscribers(例如 Activities or Fragments)处理这些事件,可以直接将数据显示到一些可以回收、重用的View上面。
【BTW:如果一个Observerble没有任何的的Subscriber,那么这个Observable是不会发出任何事件的】

这个架构的另外一个模块是event bus,event bus可以让我们在Data层发出广播(不是Android的Broadcast)然后不同的模块去注册并接收不同的广播事件

为什么这个方式这么牛逼,是因为Observables与operators可以去掉那一堆必须的回调方法

DataManager替代了传统架构中很多代码,从而使得Activity与Fragment变得更加轻量级。并且使得单元测试变得更加简单。

DataManager成为了唯一的数据交互部分,这样清晰的架构使得更方便进行代码自测。

我们还有什么问题?
- 如果对于非常庞大并且复杂的项目来说,DataManger也会变得非常臃肿并且难以维护。
- 尽管Activity与Fragment已经变得更加轻量级,但是对于错误异常的处理还是要在subscriptions的地方去书写。

一体化的MVP模式

前几年开始,很多类似MVP与MVVM在Android的一些社区比较流行,经过研究之后,我们发现MVP模式是对我们目前的方案最有价值的改动。我们的两层架构View-Data与MVP的 Model-View架构天然融合,理念一致。我们只需要增加一个presenters层,然后把之前在view实现的代码移到上面就可以了。
【转载】安卓APP架构-LMLPHP

之前的Data层就是现在的MVP中的Model,Presenter现在负责从Model中加载数据,加载完成后后再去调用左边的在Activity、ViewGroup中的方法。Presenters的subscribe去接收data manager中的Observables广播出来的数据。
举例说明,如果我们需要增加数据的过滤操作但是并不是所有地方都需要的那种,那就可以在presenter里面写这些代码,而不用写在公共的datamanager里面。

Below you can see what a public method in the presenter would look like. This code subscribes to the Observable returned by the dataManager.loadTodayPosts() method we defined in the previous section.

我们定义的dataManager.loadTodayPosts()会广播出数据给到对应的subscribes

The mMvpView is the view component that this presenter is assisting. Usually the MVP view is an instance of an Activity, Fragment or ViewGroup.

MVP的View并不是指的Android的View,而是一个界面组件的的实例,例如Activity, Fragment , ViewGroup 在注册presenter的时候,需要把自己当前的实例传递进去。

// Activity onCreate 中的代码段
if (presenter == null)
presenter = new Presenter1();
presenter.onTakeView(this);

这个架构与上一个架构不同的是,ViewLayer 也就是Activity这些,不会直接去订阅接收Observables发出的这些事件。而是只在Activity实现几个简单的显示错误、显示进度的方法(用接口interface来规范统一),然后把当前实例以参数形式传递给到对应事件的Presenter,由Presenter去执行这些显示错误、显示进度的方法。
当然对于用户交互部分的按钮点击事件还是要在Activity中进行处理。

关于MVP的文章可以自行百度一下,MVP Android 关键词

为什么这个又最吊

  • Activity与Fragment代码量大大降低,逻辑代码全部都丢给了Presenter,结果就是Activity只需要负责UI交互的按钮等代码。
  • 对于Presenter可以写单独的单元测试代码,只需要对Presenter提供的方法测试即可
  • 如果DataManager变得臃肿庞大了,我们可以分离这些代码到各自的Presenter中去。

只有一个DataManager仍旧是一个问题,尤其是当代码项目比较庞大的时候,当然我们还没有到达这个庞大的地步,尽管我们知道这个将来某天会发生。

如果想有个完美的架构解决你所有问题是不可能的。TMD Android的整个生态圈变化太快,又TM的不标准,就导致我们不断的去探索探索。。。以致于去找到更吊的方法去做Android apps。

希望读了之后对我们的最新解决方案能有些建议想法。

【本文翻译的目的是在闲暇时间,研究新技术,用通俗技术语言写给自己看,便于日后方便查阅为目】
原文:https://medium.com/ribot-labs/android-application-architecture-8b6e34acda65
MVP介绍:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0425/2782.html
RxAndroid:https://github.com/ReactiveX/RxAndroid
Eventbus:https://github.com/greenrobot/EventBus

04-16 03:10
查看更多