MVC安卓实践

MVC安卓实践

上周写了《MVC简述》,如果就这样结束MVC探索之旅,感觉还是停留在表面,前人不是有把学习过程分为几个阶段的嘛:知、学、练、熟、精。我只是达到了“知”,所以希望通过这篇文章进入到“学”和“练”的境界。

安卓出来有好多年了,刚出来的时候,差不多是09、10年吧。那时,我正在做flex,心中还有一个RIA梦,结果html 5和手机蓬勃发展,一切都变了,现在还没有回个神来。所以,前端开发要紧跟时代,只能不断学习和动作迅速。虽说很多东西再变,但也有一些没变的,就像做房子,做房子的材料在变,很久以前是木头,后来是砖瓦、再到现在的钢筋水泥,以后还不知道是什么,但是房子结构设计,比如说稳固性,一些古老的建筑至今为什么保存完好,地震的时候为什么没有倒塌,仍然是现在很多建筑师参考的范本。回到开发,MVC不管用Flex,还是安卓,都有它的意义。所以今天我就来班门弄斧一下,看看在安卓开发中怎么用MVC思想来设计。

我在这里先把这篇文章的内容、形式做一下限定。因为时间有限,不可能搞一个android的MVC框架出来,想搞,自己现在也没有那个能力。android是基于Activity的,所以在这篇文章里,我将选用一个场景或者案例来对一个Activity 进行MVC的实现。

场景

这个场景是这样的:用户有一个习惯,喜欢计帐目,所以需要一个账目清单,每有一次花销,就会把它记入这个清单里面,并且需要知道总的花销数目。


图1:用例图

放到实际功能上,可以这样说:

1,      用户打开应用后,显示一个了账单的列表,每行显示两列,一个是条目名,一个是费用。最后一行的条目名是合计,费用是上面各列的总费用。

2,      在清单下方有一个添加按钮,点击后会弹出一个对话框,里面有两个输入框,分别用于输入名称和费用;还有确定、取消按钮,当确定按钮被按下后,账单列表中会增加一行条目,并且总费用会增加。

设计分析

在这个例子中Model(模型)很好确认,模型的数据就是账单List,行为就是统计费用总和。对于View和Controller的切割可能有不同的意见。首先我们来看用户行为,有三个:

1,  添加按钮被点击,触发新建条目对话框;

2,  对话框上的确定被按钮点击,新添加一个条目,关闭对话框;

3,  对话框上的取消按钮被点击,关闭对话框。

这些行为应该放在控制器里面,但是实在是很简单,所以很多人可能就不会再创建一个控制器类来封装他们,而是把它们直接放在Activity里面。这样做也有一定的理由,因为android的视图已经用layout.xml给代替了,并且Activity负责一些窗口状态的处理,比如窗口隐藏的话,onPause方法会被调用,所以Activity天生就具备一些控制器特质。

我还是偏向于为Activity的View单独创建控制器,以独立于Activity。Activity作为窗口控制器,是View控制器的上级,所以它们分别是:

Model: 账单,负责保存所有账目,并且可以汇总。

View: 用layout.xml表示.主要有账单列表视图和添加新帐目视图。账单列表视图是主Activiy的ContentView。当点击添加按钮后,会弹出一个对话框,里面包含了添加新帐目视图。

Controller: 所有的Activity、Dialog以及对应的视图控制器。它们负责创建视图,建立视图和模型的关系以及监控用户操作、系统状态等等。

实现

实现包括各组成部分的初始化,以及之间的交互和结束。我们先来看看初始化。

初始化

在这里我们主要讨论它们初始化的位置,由谁来初始化它们。

视图控制器一般都由上级控制器(Activity, Dialog)创建。控制器内部负责监控视图上的操作,但是视图不一定初始化了,而Activity或者Dialog(更准确是DialogFragment) 知道什么时候视图被创建,继而可以交给控制器来监控用户行为。如果视图控制器由第三方创建,那么等到一定时机,需要被通知视图准备好了。而视图创建好了,只有上级控制器知道,所以这需要通过中介来达到目的,有点曲线救国的意思。

视图由Activity或者DialogFragment创建,这个不多说,android系统决定的。

模型由视图控制器创建。控制器负责读取模型数据并且负责把数据赋值给视图,这样模型将独立于Activity。在android 里没有flex或者wpf里的数据绑定的概念,不会主动读取数据,所以视图是一个被动视图,需要控制器来负责绑定数据和视图的关系。


图2:账单类图

 

交互

这里交互可以看成两部分,一部分是控制器监控用户行为、处理用户行为;另一部分是MVC各部分的通讯。

我们先看第一部分。Android设计的特别好的一点就在这里,UI所有的用户交互都可以通过设置监听器来获得。控制器主要任务就是给各个UI组件设置监听器来捕获用户行为,然后作相应处理。如果说该行为的影响范围只涉及到本视图或者本数据模型,那到这里就结束了,但是世上没有这么好的事情,不能太容易让你们这些程序员拿高工资!所以就有第二部分,需要通知app的其他部分来处理这些行为。

在本例子中就有一个这样的行为。在添加账目按确定按钮后,控制器监控到该行为,并且可以得到添加账目的名称和费用,然后需要把这个账目添加到账单中,但是该控制器没有账单信息。这个账单在哪呢?在ContentViewController里面,所以需要控制器之间的通讯。

ControllerBase实现了这个功能:它有一个控制器消息集中器,当Controller构造的时候,就会被注册到控制器消息集中器上面,所以集中器知道所有的控制器,当其中一个控制器发送消息的时候,其他的控制器都会收到该消息。如下图所示:


图3:消息传送

那么MVC之间还有哪些通讯? 理论上还有:

1,  Model和Model, Model和View,Model和Controller。

在MVC里,Model变化会引发事件或者触发监听器。View和Controller监控模型,模型不会主动去和View、控制器通讯。在android里视图是被动视图,Model引起视图变化,只能通过控制器来改变视图,所以说Model和View的通讯可以看成是Model和Controller通讯。如果控制器是Model对应的,这个问题就不是问题,因为控制器本来就用来监控Model。如果这个控制器是第三方的,我们姑且不说这是否合理,有两个途径:

l  model a -> model b -> controller b

l  model a -> controller a -> controller b

2,  View和View,View和Model、View和Controller。

a)        View 和View 可以通过控制器来传递。比如view a -> controller a -> controller b ->  view b。

b)        view 不能直接改变Model,所以需要通过控制器,所以就是View和Controller通讯的问题。

c)        View和Controller通讯也可以通过控制器之间通讯来达到。比如 view a -> controller a -> controller b。

3,  Controller和Controller, Controller和View , Controller和Model。

a)        Controller和Controller: 需要控制器间通讯。

b)        Controller和View:可以通过控制器通讯实现。比如 controller a -> controller b -> view b

c)        Controller和Model: 也可以通过控制器通讯实现。比如controller a -> controller b -> model b

所以综上分析,在不违背MVC原则下,控制器间通讯十分必要,其他的通讯都可以通过它来转发。但是怎么找到对应的控制器,比如说控制器 a需要改model b,怎么知道哪个控制器和model b对应呢?并且该控制器还存在,估计是一个问题。所以在设计模型的时候,尽量不要出现这种情况。

结束

在这个例子中,因为控制器消息集中器里面注册了所有的控制器,所以在控制器销毁前,需要向消息集中器取消注册。


代码下载


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值