小试Android中使用MVC框架模式

MVC简介

关于MVC网上的说法成千上万,每个人都有自己的理解,下面只是我个人现阶段学习的理解,欢迎指出不足之处~

MVC(Model View Controller 模型-视图-控制器)

  • Model(模型)直接操作数据层(如数据库记录的读写等),通常有最重的处理任务
  • View(视图) 直接面向用户数据展示界面,接受用户的数据输入并传递给控制层
  • Controller(控制器)业务逻辑处理层,本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据

那么,MVC各层与Android又有什么对应关系呢?

  • Model:负责数据处理相关的逻辑,通知View改变,会常涉及到网络请求及Android中的datebase、SharePreference等。
  • View:自定义View或ViewGroup,负责将用户的请求通知Controller,并根据model更新界面;  
  • Controller:接收用户请求并更新model;

下面以一个简单的登录demo示例。

使用安卓自带的SQLite建立一个用户,在登录时输入用户名和密码后匹配数据库记录,并显示登录成功或者失败的原因等。

其中,bean中User为实体类,包括用户名和密码;callback作为回调接口在控制层和模型层传递数据处理结果;db为帮助我们在数据库建立一个用户,并提供查询;

public class User {

    private String name;
    private String pwd;

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public String getName() {

        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

User

public interface LoginCallBack {
    void success(User user);
    void fail(int status);
}

 1 public class MyDataBaseHelper extends SQLiteOpenHelper {
 2
 3
 4     private static final String CREATE_LOGIN = "create table LoginInfo(" +
 5             "id integer primary key autoincrement," +
 6             "name text," +
 7             "password text)";
 8
 9
10     public MyDataBaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
11         super(context, name, factory, version);
12     }
13
14     @Override
15     public void onCreate(SQLiteDatabase db) {
16         db.execSQL(CREATE_LOGIN);
17     }
18
19     @Override
20     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
21
22     }
23
24     public void initData(SQLiteDatabase db) {
25
26         String sql = "insert into LoginInfo(name,password) values(‘test‘,‘test‘)";
27         db.execSQL(sql);
28 //        ContentValues values= new ContentValues();
29 //        values.put("name","test");
30 //        values.put("password","test");
31 //        db.insert("LoginInfo",null,values);
32
33     }
34
35     public int queryData( User user) {
36
37         String sql = "select * from LoginInfo where name=?";
38         Cursor cursor = this.getReadableDatabase().rawQuery(sql, new String[]{user.getName()});
39
40         try{
41             if (cursor.moveToFirst()) {
42                 if (cursor.getString(cursor.getColumnIndex("password")).equals(user.getPwd())) {
43
44                     return 1;//正确
45                 } else {
46                     return 0;//密码错误
47                 }
48             }
49             return -1;//用户名错误(没有当前用户)
50         }catch (Exception e){
51             e.printStackTrace();
52         }finally {
53             cursor.close();
54         }
55         return -2;//发生错误
56
57     }

先从View层讲起:自定义一个LoginView继承自LinearLayout

<?xml version="1.0" encoding="utf-8"?>
<prodigalwang.androidframe.mvc.view.LoginView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_login_mvc"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/et_name_mvc"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:layout_gravity="center_horizontal"
        android:hint="请输入用户名" />

    <EditText
        android:id="@+id/et_pwd_mvc"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:layout_gravity="center_horizontal"
        android:hint="请输入密码"
        android:inputType="textPassword" />

    <Button
        android:id="@+id/bt_login_mvc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="20dp"
        android:text="登录" />
</prodigalwang.androidframe.mvc.view.LoginView>

通常我们直接在activity中直接初始化各种控件,而我们这样做之后只不过是将布局的初始化化代码移入到自定义的view中。

 1 /**
 2  * Author:ProdigalWang
 3  * Time: 2016/9/26
 4  * 视图层,直接展示给用户。通过视图层将数据请求传送到控制层(Controller)
 5  * 作为视图层来说,它只是作为接受用户数据和展示数据的方式
 6  */
 7 public class LoginView extends LinearLayout {
 8
 9     private Context mContext;
10     private EditText mUsername;
11     private EditText mPassword;
12     private Button mLoginBtn;
13
14     public LoginView(Context context, AttributeSet attrs) {
15         super(context, attrs);
16         mContext = context;
17     }
18
19     public void initView() {
20         mUsername = (EditText) findViewById(R.id.et_name_mvc);
21         mPassword = (EditText) findViewById(R.id.et_pwd_mvc);
22         mLoginBtn = (Button) findViewById(R.id.bt_login_mvc);
23     }
24
25     public String getName() {
26         return mUsername.getText().toString();
27     }
28
29     public String getPwd() {
30         return mPassword.getText().toString();
31     }
32
33     public void setOnclikLister(OnClickListener onclikLister) {
34         mLoginBtn.setOnClickListener(onclikLister);
35     }
36
37     public void userNameEpty() {
38         Toast.makeText(mContext, "用户名不能为空", Toast.LENGTH_SHORT).show();
39     }
40
41     public void passWordEpty() {
42         Toast.makeText(mContext, "密码不能为空", Toast.LENGTH_SHORT).show();
43     }
44
45     public void userNameError() {
46         Toast.makeText(mContext, "用户名错误", Toast.LENGTH_SHORT).show();
47     }
48
49     public void passWordError() {
50         Toast.makeText(mContext, "密码错误", Toast.LENGTH_SHORT).show();
51     }
52
53     public void loginSuccess() {
54         Toast.makeText(mContext, "登录成功", Toast.LENGTH_SHORT).show();
55     }
56
57     public void loginFailure() {
58         Toast.makeText(mContext, "登录失败", Toast.LENGTH_SHORT).show();
59     }
60 }

这样我们就完成了View层的抽取。

下面实现Model层:首先我们需要先抽取出一个接口,由于我们的需求很简单,只是一个登陆操作,只需要验证用户输入的用户名和密码是否正确,所以我们的抽取的接口中也只有一个login()方法。

/**
 * 模型层———登录接口
 */

public interface ILoginModel {

    void login(String name, String pwd, LoginCallBack loginCallBack);
}
/**
 * Author:ProdigalWang
 * Time: 2016/9/26
 * 模型层实现,完成具体的数据操作。
 */

public class LoginModelImpl implements ILoginModel {

    private MyDataBaseHelper myDataBaseHelper;

    @Override
    public void login(String name, String pwd, LoginCallBack loginCallBack) {

        User user=new User();
        user.setName(name);
        user.setPwd(pwd);

        myDataBaseHelper = new MyDataBaseHelper(MyAppliction.getContext(), "Login.db", null, 1);

        int result = myDataBaseHelper.queryData(user);

        //发出处理结果,用户得到反馈
        if (result == 1) {

            loginCallBack.success(user);
        } else {
            loginCallBack.fail(result);
        }
    }
}

最后,完成Controller:

/**
 * Author:ProdigalWang
 * Time: 2016/9/26
 */
public class LoginController implements View.OnClickListener {

    private LoginView loginView;
    private ILoginModel iLoginModel;

    public LoginController( LoginView loginView){
        this.loginView=loginView;

        iLoginModel=new LoginModelImpl();
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.bt_login_mvc:
                String username=loginView.getName();
                String pwd=loginView.getPwd();

                if (TextUtils.isEmpty(username)){
                    loginView.userNameEpty();
                    break;
                }
                if (TextUtils.isEmpty(pwd)){
                    loginView.passWordEpty();
                    break;
                }
                //调用模型层去处理具体的请求
                iLoginModel.login(username, pwd, new LoginCallBack() {
                    @Override
                    public void success(User user) {
                        loginView.loginSuccess();
                    }

                    @Override
                    public void fail(int status) {
                        if (status==0){
                            //模型层完成数据处理后,通知视图层做出相应的改变。用户得到反馈。
                            loginView.passWordError();
                        }else if (status==-1){
                            loginView.userNameError();
                        }else {
                            loginView.loginFailure();
                        }
                    }

                });
                break;
        }
    }
}

那么,我们实现了MVC框架模式后,我们的Activity里的代码又变成怎么样了呢?

**
 * 此时Activity就变为了承载视图层的容器。
 */
public class MvcLoginActivity extends AppCompatActivity {

    private MyDataBaseHelper myDataBaseHelper;
    private SQLiteDatabase db;

    private LoginView loginView;
    private LoginController loginController;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mvc_login);

        //初始化一个本地用户用来模拟登陆。
        myDataBaseHelper = new MyDataBaseHelper(this, "Login.db", null, 1);
        db = myDataBaseHelper.getWritableDatabase();
       //myDataBaseHelper.initData(db);

       MVC();
    }

   private void MVC(){
        //控件初始化和绑定
        loginView= (LoginView) findViewById(R.id.activity_login_mvc);
        loginView.initView();

        loginController=new LoginController(loginView);//视图层结合控制层
        loginView.setOnclikLister(loginController);
    }
}

没错,这个时候activity里面的代码就是如此的少。关键之处的代码注释写了,这里就不做详细解释了。

那么,来总结一下整个流程:首先用户打开应用,loginView.initView()调用,显示整个布局。这时候用户输入用户名名和密码后点击登录按钮,Controller层通过View层的getName()和getPwd()获取到用户输入的数据,紧接着Controller层会调用Model的接口中的login()方法,将数据传递给Model层进行具体的处理。当Model完成处理后,会通过LoginCallBack回调处理的结果,并通知View层进行视图的改变,这是用户得到反馈结果。

最后,总结一下MVC带来的好处与不足 :

好处:1.总所周知,采用各种各种框架模式都是为了实现高内聚低耦合,实现分层能够实现良好的分工合作,各层独立,修改哪一层对其他层的影响都能降低很多。

2.重用性高,由于模型返回的数据没有进行格式化,所以同样的构件能被不同的界面使用。例如,很多数据可能用HTML来表示,但是也有可能用WAP来表示,而这些表示所需要的命令是改变视图层的实现方式,而控制层和模型层无需做任何改变。

3.维护性高,部署快。不同的开发人员只需要专注于一层的实现。

不足之处:1.不适于小型程序,如果我们在小程序上为了实现MVC框架模式而实现的话,会浪费大量不必要的时间和精力。

2.增加系统结构和实现的复杂性等。

参考资料:

1.http://baike.baidu.com/link?url=3hzUtpjpvrAJCJwjQ1OlGZZVU7Ri_7cXK0gZSqZf-IuR7sRpNRruaG6TtpV3tgJNWQ6l4YR4N6pyk99j3TX9Y2aj1yBAb837M2cLMK5J5MUEBCyjzmVOhT_3Q2_HDPMv

2.https://github.com/jpush/jchat-android

时间: 2024-12-15 01:40:34

小试Android中使用MVC框架模式的相关文章

简述MVC框架模式以及在你(Android)项目中得应用

标题是阿里电话面试的问题,一直以为自己很清楚MVC模式,结果被问到时,这M.V.C这几者之间的关系都搞不清楚了,最主要是,没法将MVC和Android中各个组件对应起来,所以,面试肯定挂了,不过面试也是学习的一种方式,可以知道大公司看中什么,以及自己还有哪些知识漏洞,例如这次面试就学到了很多东西. 大家也可以在看下面的内容之前,也想想能否把MVC及与Android各个组件的对应关系讲清楚,看是否还有和我一样对MVC一知半解的.  如果写的有问题的地方,欢迎讨论.转载请注明出处:http://ww

Unity3d 基于网络使用SendMessage 及 基于网络使用Delegate的客户端MVC框架模式(一)

作为一个大型游戏,不可避免需要使用复杂的界面.网络消息处理.数据缓存等一些略微复杂的东西.其实我们都知道,对于一个手游来说,庞大的系统工程下面,其实是大量基础的技术的堆叠.于是在游戏开发中,出现各类的Bug其实并不是因为技术上的实现出现问题,而是从框架.代码的管理上出现设计失误. 转载请注明出处 文章出自 http://blog.csdn.net/huutu QQ790621656 http://www.thisisgame.com.cn 针对以上问题,众多软件设计者做出努力,设计出了很多中逻辑

MVC框架模式技术实例(用到隐藏帧、json、仿Ajax、Dom4j、jstl、el等)

前言: 刚刚学完了MVC,根据自己的感悟和理解写了一个小项目. 完全按照MVC模式,后面有一个MVC的理解示意图. 用MVC模式重新完成了联系人的管理系统: 用户需求: 多用户系统,提供用户注册.登录功能,对于没有登录的用户,不允许使用任何功能. 可以查询.增加和删除联系人信息. 详细设计: 数据结构设计. 功能模块设计. 工具类设计. 搭建初步的项目框架.其他功能:防止用户重复提交.注册和登录时使用验证码. 项目代码在后面. 演示效果: 主页: 注册页面: MVC介绍: MVC全名是Model

MVC框架模式(二)

上一篇文章对MVC框架模式做了简要概述并且在文章的最后给出了MVC3个组件之间相互工作的逻辑图,在本文我们将进一步对模型(model)-视图(view)-控制器(controller)各自的概念及他们之间协同工作的原理进行剖析. 模型(Model) 业务逻辑.封装了业务逻辑和数据 业务逻辑(软件的核心) 数据以及访问它们的函数(视图组件使用) 执行特定应用程序处理的过程(控制器代表用户调用) 模型对于用户来说是不可见的(M与V独立) 模型独立与特定输出表示或者输入方式(M与C独立) 用户只能通过

MVC框架模式和Javaweb经典三层架构

一.MVC设计模式 1.MVC的概念 首先我们需要知道MVC模式并不是javaweb项目中独有的,MVC是一种软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller),即为MVC.它是一种软件设计的典范,最早为Trygve Reenskaug提出,为施乐帕罗奥多研究中心(Xerox PARC)的Smalltalk语言发明的一种软件设计模式. 2.MVC的详解 虽然MVC并不是Java当中独有的,但是现在几乎所有的B/S的架构都

采用Android中的httpclient框架发送get请求

/** * 采用httpclientGet请求的方式 * * @param username * @param password * @return null表示求得的路径有问题,text返回请求得到的数据 */ public static String httpclientGet(String username, String password) { try { // 1.打开一个浏览器 HttpClient client = new DefaultHttpClient(); // 2.输入地

采用Android中的httpclient框架发送post请求

/** * 采用httpclientPost请求的方式 * * @param username * @param password * @return null表示求得的路径有问题,text返回请求得到的数据 */ public static String httpclientPost(String username, String password) { try { // 1.打开一个浏览器 HttpClient client = new DefaultHttpClient(); // 2.输

Android中的创建型模式总结

共5种,单例模式.工厂方法模式.抽象工厂模式.建造者模式.原型模式 单例模式 定义:确保某一个类的实例只有一个,而且向其他类提供这个实例. 单例模式的使用场景:某个类的创建需要消耗大量资源,new一个对象代价太大,如访问IO和数据库等资源,或者避免多次创建该对象消耗内存过多. 懒汉模式 public class Singleton{ private static Singleton instance; private Singleton(){} public static synchronize

[转] Android中的设计模式-备忘录模式

转自Android中的设计模式-备忘录模式 定义 备忘录设计模式的定义就是把对象的状态记录和管理委托给外界处理,用以维持自己的封闭性. 比较官方的定义 备忘录模式(Memento Pattern)又叫做快照模式(Snapshot Pattern)或Token模式,是GoF的23种设计模式之一,属于行为模式. 定义:在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 角色 笔记本:很多的内部状态需要被建立一个备忘录来管理,创建和取出