Android MVC Part7 State Pattern

这部分的内容是之前答应过之后再说的状态模式,这个模式在 TapController 用到。与 MVC 和 DAOs 不同的是,我不会把状态模式归为 android 程序架构必须实现的部分。然而,它的确非常有用。因为我在 TapController 中用它来处理消息,所以还是有必要说一下。 ##状态模式 在之前的系列中我没有提到它是怎样在 android 里工作的。但是在这部分,我们将会更深入一些来探讨它。状态模式是一个面向对象的模式,目的是可以动态切换对象的行为。还记得对象具有属性和行为吗?你会觉得这听起来像是策略模式?对,你说得没错。这里不同的地方就是模式的意图。状态模式是根据属性的不同而改变其行为的。客户端甚至不知道调用的对象已经发生转换。那么是怎么做到动态切换而接口不变的?我们需要把行为封装到对象内部,然后让他妈共享一套接口。接下来我们聊聊具体的例子,这个例子就是 Tap Counter 工程了。 我们要看的连个对象叫做 UnlockedState 和 LockedState。当 CounterVo 设置为被锁,这意味着我们不希望属性改变。例如,如果用户点击了增加按钮,如果状态是锁住得话,值将不会增加。但是如果不是锁住的状态,用户点击将会使值增加。这是基于 CounterVo.locked 的两种不同行为。 当 TapController.handleMessage 被触发,它就会把消息代理给其中一种状态。这里使用了 Controller.messageState 来确定用哪一种转台。让我们看看代码吧。 :::java @Override public boolean handleMessage(int what) { return messageState.handleMessage(what); } 这的确非常简单,但是 messageState 的状态是如何改变的呢? 两个状态之间是彼此知道对方的。当 UnLockedState 接到 MESSAGE_UPDATE_LOCK 这个消息时,它就会把 messageState 的引用改为 LockedState 。然后当 MESSAGE_UPDATE_LOCK 消息被 LockedState 处理时它会更细 messageState 的引用到 UnlockedState。我觉得我们看看代码会更好理解一些。 :::java package com.musselwhizzle.tapcounter.controllers; public class UnlockedState extends TapState { // ....

November 16, 2013

Android MVC Part6 Persistence

最难的 MVC 已经讲解过了。如果你可以在 android 上实现 MVC, 这系列剩下的部分将会很容易。奖赏一下自己吧,接下来我们要讨论一下数据持久化。 我会默认你已经知道 sqlite 和其他 android 中持久化的方法。如果不知道,现在是时候去补补了。我会建议你了解 Data Access Objects 或者叫 DAOs 的概念。这个概念非常简单:我们传递一个模型的实例给 DAOs ,由它来保存,更新或者删除数据。再也不用编写一大堆 sql 语句了。妈妈再也不用担心我调用数据库了。废话不说,看看代码: :::java public class CounterDao { protected static final String TABLE = "Counter"; protected static final String _ID = "_id"; protected static final String LABEL = "label"; protected static final String COUNT = "count"; protected static final String LOCKED = "locked"; public CounterDao() { // } public ArrayList<CounterVo> getAll() { // ....

November 15, 2013

Android MVC Part4 The Controller

在 MVC 的三个部分中,控制器是最繁忙的。回顾一下,模型只是一个比较优雅的键值对象。一个好的视图是一个呆子,它只是当模型改变的时候更新自己和控制器告诉他什么就做什么。而控制器主要做三件事: 更新模型 处理视图传过来的信息 发信息给试图 这里我们主要关注后面两件事情。 ##处理消息 在所有部分当中,控制器获取消息的实现是最随意的,主要决定权在你手中,它不需要多态。你不需要跟着教程来做。而下面只是我的实现方式。但要记住 MVC 只是一个框架,不需要太注重细节,你应该关注你想要实现什么。下面是 TapListController 的示例代码。 为什么选取 TapListController 而不是 TapController ?坑爹吗? 其实主要是因为 TapController 实现了 状态模式来代理消息。所以选择 TapListController 这个更简单的类来说,以避免越说越乱。 :::java public class TapListController extends Controller{ public static final int MESSAGE_GET_COUNTERS = 1; public static final int MESSAGE_MODEL_UPDATED = 2; public static final int MESSAGE_DELETE_COUNTER = 3; public static final int MESSAGE_INCREMENT_COUNTER = 4; public static final int MESSAGE_DECREMENT_COUNTER = 5; private ArrayList<CounterVo> model; public ArrayList<CounterVo> getModel(){ return model; } public TapListController(ArrayList<CounterVo> model){ this....

November 14, 2013

Android MVC Part5 Putting It Together

之前我们已经讨论了模型(Models),视图(Views)和控制器(Controllers)。现在我们需要把他们组合在一次成为真正符合 MVC 规范。 Activity 是我们程序的每一个新视图的入口, 我们需要在 Activity 的 onCreate 方法实例化模型和控制器。其实一个典型的 MVC 模型视图是不会去实例化模型和控制器的,但是..android 有点特殊。模型一旦创建了,我们需要把 activity 注册到模型中。再者,如果你想从控制器获取消息,你也需要向控制器注册。让我们看看他们长什么模样的。 ##Activity: :::java @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); counter = new CounterVo(); counter.addListener(this); controller = new TapController(counter); controller.addOutboxHandler(new Handler(this)); // ... other set up code like referencing widgets/views ... } 这里视图在模型和控制器上都注册了。让我们看看模型对于视图的回调函数。 :::java @Override public void onChange(CounterVo counter) { mHandler.sendEmptyMessage(UPDATE_VIEW); } 一旦模型通知视图有改变,我们就在 UI 线程修改 UI控件。这就是你数据的绑定。现在让我们来看看处理从控制器发来的信息。 :::java @Override public boolean handleMessage(Message msg) { switch(msg.what) { case TapListController....

November 14, 2013

Android MVC Part2 The Model

##MVC 基本概念 MVC 是一些设计模式组合在一起的框架模式。其中的模型(The Model)代表着程序的状态。要知道,对象(Object)由状态(属性)和行为(方法)组成。所以程序也要状态(The Model)。本质上, models 是一个键值对象,当里面的状态改变的时候发送事件。视图(The View)是用户看到并与之交互的对象。视图作为观察者绑定到模型中,当模型的状态改变,视图会得到通知并作出相应的更新。当用户与视图交互,视图会发送事件给控制器(The Controller)。控制器的作用就是处理输入逻辑,它解释用户的手势,更新模型,而且向视图反馈信息。下面是它们的关系图。 ##本项目的Model 在这个项目中,最主要的模型是 CounterVo 代码如下 :::java package com.lingavin.tapcounter.vos; public class CounterVo extends SimpleObservable<CounterVo>{ private int id =-1; public int getId(){ return id; } public void setId(int id){ this.id = id; notifyObservers(this); } private int count = 0; public int getCount(){ return count; } public void setCount(int count){ this.count = count; notifyObservers(this); } private String label=""; public String getLabel(){ return label; } public void setLabel(String label){ this....

November 13, 2013

Android MVC Part3 The View

##什么是视图? 在 Android 中很多同学说 View 就是视图。但是 View 只有显示的能力,它不能处理响应和发送消息。先来看看视图的特点: 绑定模型 发送信息给控制器 处理控制器返回的信息 看来 activity 符合我们的要求,它可以绑定,可以处理信息,而且控制着 android 中所谓的 view 。但是 activity 又有一些其他的特性使它不像是 MVC 中的 V ,例如它管理着生命周期,而且它有一些像控制器的方法 boolean dispatchKeyEvent(KeyEvent event); boolean onOptionsItemSelected(MenuItem item); void onCreateContextMenu(….); so on…. 要知道 dispatchEvent 如果返回 true 表示这个 activity 会处理该事件。但是实际上,处理事件的逻辑应该交给控制器做的。 我们通过一些方法来避免上述的问题,使 activities 更像是一个视图。其灵感来源于这篇文章 为了把 activity 变成 view ,我们做了下面的操作。 ##1. 数据绑定 来看看 TapActivity 是如何绑定数据的 :::java package com.lingavin.tapcounter.activities; import com.lingavin.tapcounter.R; import com.lingavin.tapcounter.R.layout; import com.lingavin.tapcounter.vos.CounterVo; import com.lingavin.tapcounter.vos.OnChangeListener; import android.app.Activity; import android.os.Bundle; import android....

November 13, 2013

Android MVC Part1 Intro

##about 一直想寻找 android 关于基于 mvc 开发的教程, 但是国内的网站都讲得很空泛,最后在一个外国的 blog 里看到一系列的文章,介绍得很详细和具体,而且是基于项目的,所以转过来了。 这系列的文章不仅简述 MVC,还涉及到了状态模式的运用,如何用 Data Access Objects 来持久化数据,使用 web service 的命令来传递数据。这系列文章假设你已经了解用这些技术的好处,所以不会详细讲解为什么要这么用。 你可以通过点击这里查看原blog。 ##包管理 第一章先来建立工程并取好包名。好的包管理可以使明确你的类的大致作用,对编程有很大的帮助,试想下如果把所有 class 放到一个包中,当项目变大后,你想修改其中一个 class 将会是个噩梦。这里提供一个比较好的包的分类。 activities controllers daos lists models utils vos widgets 注意到所有的包名都是复数,因为里面不止一个 class 。上面的包名如果项目用不到可以删除。由包的名字我们就可以知道里面的类大致的功能,这就是好处。 activities – 很明显,这里会放入所有的 activity controllers – View 的大脑就放在这里面了 daos – 这里存放持久化逻辑 lists – 这里存放所有 list adapter models – 这里存放 View 绑定的 Model utils – 存放静态类和工具类 vos – 存放 Value Objects 也就是 POJOs 又或者 Data Transfer Objects widgets – 借鉴于android 存放定制化 widget part1 就到这里,源代码可以在这里下载 https://github....

November 12, 2013