Android APP Architecture

前言

老板让我搭建一个APP,我该怎么快速上手?
现在常用的Android应用总体架构是什么样的?
Android开发现在有哪些流行的新技术和工具,可以提高我工作效率?
这里介绍这样一个工程模板,让你快速搭建健壮(strong),易扩展(scalable),易测试(testable),易维护(maintainable)的Android工程。
什么是架构
本文主要讨论Android软件架构,那么何谓软件架构?软件体系结构是构建计算机软件实践的基础。与建筑师设定建筑项目的设计原则和目标,作为绘图员画图的基础一样,软件架构师或者系统架构师陈述软件架构以作为满足不同客户需求的实际系统设计方案的基础。软件的架构是后续软件开发实施的规则和骨架,好的架构可以极大地降低软件的开发成本和维护成本。

Android开发架构的演进

Android应用架构在一直演进,没有最好的架构,只有最适合的架构。通过对历史过程中的架构的了解,可以了解每个架构的优缺点和适用范围,知道为什么我们经历了这些变化。

MVC

MVC模式最早由Trygve Reenskaug在1978年提出。目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。它将软件系统分为三个部分:模型,视图和控制器。

MVC结构图

MVC在Android上的应用

  • View:对应于xml布局文件
  • Model:模型数据
  • Controllor:对应于Activity业务逻辑,数据处理和界面相应

MVC的问题

这里引用一段苹果开发者网站对MVC的论述

However, there is a theoretical problem with this design. View objects and model objects should be the most reusable objects in an application. View objects represent the "look and feel" of an operating system and the applications that system supports; consistency in appearance and behavior is essential, and that requires highly reusable objects. Model objects by definition encapsulate the data associated with a problem domain and perform operations on that data. Design-wise, it's best to keep model and view objects separate from each other, because that enhances their reusability.

意思大致是:View和Model都是需要重用的模块,在MVC中View监听Model的通知导致View依赖了Model,降低了View的可重用性。现实中常常在Android上实现的MVC里,View是xml文件,Activity是Controller其中又包含了大量和Model数据耦合的代码又要响应用户事件,导致承担功能过多,代码量过大难以维护和测试。而且如果修改了Model的代码,也可能会影响Activity中的逻辑。所以大型的工程,往往需要将Activity中一些和界面无关的职责拆分出来,提高工程的可维护性和可测试性。

MVP

为了彻底的将Model和View解耦,MVP对MVC进行了一些改进,将View和Model之间的通知和调用去掉,所有的数据流都经过Presenter。


MVP结构(把Controller改为Presenter)

MVP的案例

这里可以参考google在github上的示例。这个工程里面实现了很多架构,每个架构都是单独一个分支,其中分支TODO-MVP就是演示的MVP。下面简单解读一下这个工程:
1 工程结构

todomvp工程结构
  • 按照功能模块划分包
    本工程按照不同的功能来分包,如todoList,taskdetail,statistic(统计页面)等,每个功能都是相对独立的。通常来讲,我们可以用功能分包或者按照层次(如view,presenter,model等)来分包。关于那种分包模式好,Clean Architecture的作者做了一些有意义的论述,其中旗帜鲜明的支持按照功能分包。
  • 功能模块的结构
    在每个功能模块中,主要包括了该功能的Activity、Fragment、Presenter、Contract四个类文件。Activity用于创建Presenter和View,Fragment实现了View的接口,Presenter实现了各项逻辑,Contract用于把Presenter和View联系在一起。Model在各个功能模块之外,为各模块提供支持。

2 MVP在工程中的使用

  • 使用contract把同一个功能的view和presenter联系在一起,如:
public interface TasksContract {
    interface View extends BaseView<Presenter>{}
    interface Presenter extends BasePresenter{}
}
  • Fragment继承View,来实现界面的具体逻辑
public class TasksFragment extends Fragment implements TasksContract.View {
}
  • 在Activity中构造Presenter和View
TasksFragment tasksFragment =
                (TasksFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);
        if (tasksFragment == null) {
            // Create the fragment
            tasksFragment = TasksFragment.newInstance();
            ActivityUtils.addFragmentToActivity(
                    getSupportFragmentManager(), tasksFragment, R.id.contentFrame);
        }
// Create the presenter
mTasksPresenter = new TasksPresenter(
                Injection.provideTasksRepository(getApplicationContext()), tasksFragment);
  • 在Presenter里处理各类逻辑
public class TasksPresenter implements TasksContract.Presenter {
    @Override
    public void loadTasks(boolean forceUpdate) {}
    @Override
    public void addNewTask() {}
}

MVP的问题

那MVP会有什么问题呢?试想一下下面的场景:假设要实现一个类似QQ的最近会话列表功能,那么可以从服务器拉到一个最近会话的列表如下[{id:1,message:"hello1"},{id:2,message:"hello2"}],列表中每一项有一个id和一个最近消息。好了,这样就可以显示这个会话列表了。可是过了一段时间,产品又要求如果最近会话里面有好友,需要显示好友的备注,而不是id。这时我们不得不又向服务器请求好友列表,然后把是好友的id替换为备注名显示在界面上。这里就出现了一个问题,当程序中已有一个功能是显示好友列表,此处实现了一套拉取好友列表的功能了,而现在又需要再重复实现一次。聪明的读者这个时候也许已经想到了一个解决方案,把两个功能重复的地方拿出来实现,从而达到重用的目的。

Clean Architecture

为了解决上面的问题,就有人提出了Clean Architecture的架构。架构图如下:

Clean Architecture

  • 依赖是由外向内的,最外层蓝色的包括UI,Model(本地数据库或网络数据),绿色层是Presenter,红色层是Use Case,这里的Use Case指的就是外层可重用的模块,如上文中提到的好友资料相关的逻辑,黄色层称为Entities为更基础的模块,如整个APP可共用的逻辑,或者一个公司所有APP都可以共用的模块(如果程序比较简单,就没有这一层)。
  • 每一层都有单独的数据结构,数据从一层到另一层的时候都需要经过转换,如果不希望这个程序都使用同样的数据结构的话,这么做是值得的。
  • 具体的实现我们还是参考google的demo,如图所示:
    mvp-clean实现

    整个工程分三个模块,分别是Data,Domain,Presentation。Data是原MVP中的Model,在Clean Architecture中处于最外层;Domain处于Use Case层,用于实现各个可以重用的业务模块;Presentation包含了UI和Presenter和自己的Model
  • 独立的UI,独立的数据库,独立的业务逻辑,更易测试和维护

Clean Architecture的案例

这里解读一下google的工程,如下图:


todo_clean工程结构

可以看到这个工程和前文的MVP工程结构没有太大变化,只是在功能模块中加入了domain目录,里面实现了Use Case。

RxJava和Dagger

在工程整体结构确定了后,这里还可以使用时下比较热门的两个库,帮助我们写出更优美,更易测试的代码。

RxJava

RxJava是用于压缩异步操作的库,可以让多层callback回调变成一串连续的事件,从而减少层次让代码更简洁。更多详细介绍

Dagger

Dagger是一个轻量级的依赖注入库。关于Dagger2的使用方法可以参考这里。使用Dagger的主要好处包括:

  • 依赖是在外部注入和配置的,所以方便了模块的可重用性
  • 可以注入抽象类和接口,从而更好的解耦
  • 可以注入mock的依赖,方便测试

工程地址

这里实现了一个Clean Architecture + RxJava + Dagger的框架示例, 该示例使用了必应中国的每日图片API。

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

推荐阅读更多精彩内容