[译]Designing the Android Application Architecture

原文:https://medium.com/@ravisahani28/designing-the-android-application-architecture-50bbdf34840d

设计Android应用程序架构:

多年来,Android开发已经发生来很多的变化,技术栈也变得越来越完善,开发者希望能编写出整洁,松耦合,可维护和易于理解的高质量的代码,这边文章将简要介绍如何使用Clean结构去设计Android应用程序。

Clean Architecture

这个架构由Robert C. Martin(鲍勃叔叔)于2012年在 clean code blog.
提出。

为什么要采用更Clean的方法?

  • 通过职责分配将不同层中的代码分隔开来,这样代码维护会变得更容易;
  • 高层次的抽象
  • 代码的松耦合
  • 单元测试更容易;
    “整洁的代码看起来总是像是有人在乎的。” -迈克尔·费瑟斯(Michael Feathers)

架构:

强大的基础架构对于应用程序的扩展和更快的开发需求至关重要。我所就职的Rebel公司恰好有一个全新的项目需要开发,用来合并我们没办法在现有项目中添加的功能。这篇文章说明来我们决定重新开发一个新的应用而不在程序上继续加功能的缘由
因此,在开始项目之前,我们作为对程序架构设计做了一些思考。什么是好的架构?能让我们团队中的开发者发挥出最大生产力的才是好架构。
在制定研发计划的时候,我们考虑了每一个模块,工具,功能,库,架构层之间的通信(即数据层,界面层,业务逻辑层)等。来保证团队开发能不浪费时间在底层代码上,避免一些简单的错误,也让我们能更容易的实行代码审查,更专注于业务功能的实现。
我们采用Clean Architecture的概念来解决我们的问题,并且在我们的项目中引入来Android的组件,以保证我们的结构的尽可能的松耦合。

网络请求:

在Android应用中,网络请求是不可避免的,比如加载一张网络上的图片,或者是与你的服务进行通信,都是要进行网络连接的。
很多时候,我们在做开发的是,后台服务都是并行开发的,这就意味着,我们在做某个功能的时候,后台接口可能还没开发完成。而你能做的,就是与后台开发人员定义好服务请求的数据结构。这样就不会影响开发进度。
那Android开发人员怎么样才能做到不与后台交互的情况下对功能进行测试和开发呢?
这里我们用RetrofitOKHttp来解决这个问题,OKHttp 2.2中引入来InterCeptor,它能在你的http请求中插入钩子,以便你可以拦截所有请求和响应。这是我们决定在项目中使用Retrofit进行联网的原因之一。
下面是我总结的Retrofit的优点:

  1. Retrofit是一个基于OKHttp封装的类型安全的RESTful 网络请求适配器,它能让我们的网络请求方法简化。
  2. Retrofit针对URL操作,网络请求,加载,缓存和多线程和同步都做了优化。
  3. 它支持同步和异步调用,简化来开发的复杂度。
  4. Retrofit 几乎能用于所有网络请求接口。
  5. Retrofit通过拦截能使用GSON或者Jackson对Api请求和响应进行解析,来简化开发复杂度。
  6. Retrofit使用注解来减少样板代码。开发人员能将更多的精力用在功能的实现上。

图像加载和缓存:

对于图像的加载和缓存,我们有Glide,Picasso,Volley,NetworkImage,Fresco等第三方库。在我们的程序中,我们需要播放Gif和加载缓存图像,所以我们决定使用Glide来进行图像的加载。
下面是我总结的Glide的优点:

  1. 它提供了更快,更高效,更易用的方法在Android中加载图像。
  2. Glide支持获取,解码,显示视频截图,Gif和图像缓存
  3. Glide里有灵活的的API,让开发人员能使用任何网络请求库进行图片的网络请求加载。
  4. Glide注重于解决如何平滑,快速的在滚动的图像列表中加载图像。
  5. 它还能防止程序因为图片加载引起的OOM异常。

离线数据存储:

因为业务需要,我们需要将数据保存在本地,Android框架中自带有SQLite数据库。
但是使用原生的数据库来存储数据,我们需要用ContentProvider来编写SQL语句,这样不仅增加来很多样板代码,而且降低来代码的可重用性。
随着代码量的不断增加和团队规模的扩大,我们开发一个功能所需要的时间也会越来越多,且代码的维护成本也会增大。

  1. 因此,我们提出一个解决方案,就是用ORM数据库框架来存储数据。ORM能减少开发人员在处理底层数据库花费的时间,而且通过将Java对象映射到数据库表(ORM,“对象/关系映射”),它可以让你不需要编写太多的SQL语句。这样,你就可以用简单的面对对象的API来对数据进行增删改查了。
  2. 下面是我们列出的几款ORM数据库框架:
    a) Room
    b) SugarORM
    c) Realm
    d) GreenDao etc.
  3. 最后我们决定使用Room,因为Google在最新的Android架构组件中引入了它。它可以减少样板代码,并且能轻松的将SQLite数据表的转换称Java对象。
  4. Room还提供了SQLite预计的编译时检查,并且它可以与Rxjava结合使用。我们将在下一篇文章中深入研究Room数据库框架。
Room数据持久化库

架构模式(MVP,MVC,MVVM):

在项目开始的时候没有选择适合的架构模式是一个错误的做法。
这将会导致以下问题:
a) 这会让你无法跟踪一个复杂类里面的逻辑。
b) 接手你的项目的开发人员会很难维护你的代码和在代码中增加新功能。
c) 调试会变得异常的困难,因为一个类里面包含了太多的功能。
d) 无法很好的执行单元测试。
因此。我们想要构建一个高质量的项目,就必须有一个合适的项目架构。
在Android中,最著名的三层架构模式有以下几种:

  1. MVC: Model-View-Controller
  2. MVP: Model-View-Presenter
  3. MVVM: Model-View-ViewModel

在这几种架构中,我们最后决定使用MVVM架构模式来构建我们的项目。

数据在不同层间的流转

Google引入了Android architecture components来支持MVVM架构模式:
a) Room, LiveData, ViewModel, Paging, WorkManager and Navigation.
b) 通过它们能解决复杂的架构问题,例如管理Android生命周期(LiveData/ViewModel), or 或者处理后台任务 (WorkManager).
c) 它是基于观察者模式,能减少样板代码的编写,加快构建效率,让我们能专注与业务功能的实现。

关注点分离:

在设计代码架构的适合,要遵循的最重要的原则,就是关注点分离。开发人员经常将所有代码写在一个类里面。只是一个很常见的错误,例如Android中的Activity或者Fragment。

关注点分离

在程序结构里,构建分层应用的关键在于关注点分离。在传统的N层架构体系中,层有可能包括了数据访问层,业务逻辑层,和界面展示层。
除了通过分层的方式来分离逻辑之外,还可以根据程序功能来分离关注点,将程序的功能模块化。
依照这个原则是项目更加容易维护和扩展,也能让我们不会那么容易的违反 Don’t Repeat Yourself principle这个基本原则。
“[关注分离],即使不能完全实现,但这也是我所知道但唯一能有效整理思想的可用技术。”---埃格·迪克斯特拉(Edsger W. Dijkstra)

单一数据来源:

在信息系统设计和理论中,Single Source of Truth (SSOT)
是一种构造信息模型和关联图式的时间,这样每一个数据元素只会存储一次。

在应用程序中使用单一的数据来源,我们确保我们的数据始终来自一个来源,即我们的数据库。在这个模型中,数据库是唯一的可信数据来源,而程序的其他模块则通过repository或者Managers来获取数据(这里repository或者Managers是获取数据的唯一连接)。

单一数据来源

Repository可以有以下实例:

  1. Remote(远程数据,例如通过api进行网络请求获取数据)
  2. Database(数据库,例如通过数据库存储和获取数据)
  3. Cache or Shared Preferences(缓存或者Shared Preferences)

这里Repository根据关注分离原则属于N层架构中的数据层。
我们使用了LiveData,Retrofit,LiveDataCallAdapter和Room来使我们的应用遵循单一数据来源原则。下面是示例代码,在接下来的文章中,我们介绍其设计原理和实现:

fun getProducts():LiveData<DataResponse<Product>>{
    return object :NetworkDbBindingResource<Product, Product> () {
    
   /* Store the Products in the Room Database.*/
   override fun storeApiResult(@NonNull item:Product){
        ProductDbManager.addProducts(item) 
    }
    /*  Return Product list data from the database.
    i.e Single Source of Truth to access data from one source */
    
    @NonNull
    override fun loadFromDb():LiveData<Product> {
        return ProductDbManager.getProductListLiveData() 
    }
    /* If true then it will fetch the data from the server 
    using Api call. 
    If false then it will return the data from the database. */      
 
    override fun shouldAlwaysFetchData():Boolean {
        return true or
        false 
    }
    /* If condition shouldAlwaysFetchData() = false then it 
    will  fetch  from the database
    If condition shouldAlwaysFetchData() = true then it will 
    fetch the data from the server using api call and 
    store the results in the Database. */
    override fun shouldRefreshData(@Nullable data:Product ?):
     Boolean {
        return true or false 
    }
    /* Retrofit Network Call to fetch data from the server. */
    @NonNull
    override fun createCall():LiveData<DataResponse<Product>> {
        return ProductApiManager.getProducts() 
    }
  
  }.resultLiveData
}

SOLID原则:

SOLID是五个单词的首字母缩写词,用来定义五个面向对象的基本设计原则,SOLID原则可以确保我们的代码体系结构实现可伸缩性,灵活性和功能扩展。


SOLID原则
  1. 单一责任原则
  2. 开放封闭原则
  3. 里氏替换原则
  4. 接口隔离原则
  5. 依赖倒置原则

现在我们已经设计好了我们的项目代码体系结构,现在是时候动手来实现它来,接下来的博客中,我们将讨论如何在我们的框架中实现上面内容。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,295评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,928评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,682评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,209评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,237评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,965评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,586评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,487评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,016评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,136评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,271评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,948评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,619评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,139评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,252评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,598评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,267评论 2 358

推荐阅读更多精彩内容