浅谈Android中的MVC与MVP模式

使用MVC或者MVP模式会增加很多的类,但是确可以让代码结构变得清晰,方便了后期维护拓展方便。把数据层跟视图层分离,处理事务的逻辑单独的放在一个类中,让Activity仅仅具有展示功能。

下面我们就MVC模式跟MVP模式进行分别讲解,总之来说各有利弊。在实际的开发中,我们根据实际情况进行取舍。个人认为MVP模式更简单一些,因为MVP模式中会把部分逻辑Activity中,但是这就造成了Activity的相对繁琐,没有实现完全的隔离。而我们采用的MVC模式则是更好的处理了这个问题,但是在应用的过程中,部分逻辑可能比较绕。

下面我们通过一个用户登录这个例子来分别理解这两种模式。

首先来讲解MVC模式:

这里说将对MVC模式不是传统的MVC模式,感谢极光推送IM提供的demo,这个demo所采用的就是一种MVC模式,具体的实现思路是将model层,view层,controller层分离,而Activity只是用来加载视图使用,初始化控件交给view层,对数据的获取交给model层,对数据的处理交给controller层,我们的Activity是异常的清爽!

首先我们来设计view层,自定义一个view,继承自我们需要的viewgroup,LinearLayout或者FrameLayout等。我们自定义的目的是为了下一步实例化控件,从而不必在Activity中实例化了。这里我们只是简单的继承,通常不需要自己多加逻辑,所以不要慌。代码如下:

public class LoginView extends RelativeLayout{

    private Context mContext;

    /**
     * 因为我们是在布局文件中使用,所以只需要重写这个构造方法就可以了
     * @param context
     * @param attrs
     */
    public LoginView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
    }

}

现在我们就使用已经定义好的viewgroup来进行布局,只是一个简单的登录窗口,一个用户名,一个密码,还有一个登录按键:

<?xml version="1.0" encoding="utf-8"?>
<com.baiyyyhjl.mode.mvc.view.LoginView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/et_username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="用户名"
        android:padding="10dp" />

    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/et_username"
        android:hint="密码"
        android:padding="10dp" />

    <Button
        android:id="@+id/btn_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/et_password"
        android:padding="10dp"
        android:text="登录" />
</com.baiyyyhjl.mode.mvc.view.LoginView>

现在我们在LoginView中添加控件的初始化的方法。

public void initModule(){
        mUsername = (EditText) findViewById(R.id.et_username);
        mPassword = (EditText) findViewById(R.id.et_password);
        mLoginBtn = (Button) findViewById(R.id.btn_login);
    }

获取到EditText中的内容,以及对mLoginBtn点击事件的监听,这里我们可以添加更多关于view的操作,一切根据实际需求来:

    public String getUserName(){
        return mUsername.getText().toString().trim();
    }

    public String getPassword(){
        return mPassword.getText().toString().trim();
    }

    public void setListeners(OnClickListener onClickListener){
        mLoginBtn.setOnClickListener(onClickListener);
    }

    public void userNameError(Context context){
        Toast.makeText(context, "用户名不能为空", Toast.LENGTH_SHORT).show();
    }

    public void passWordError(Context context){
        Toast.makeText(context, "密码不能为空", Toast.LENGTH_SHORT).show();
    }

    public void loginSuccess(Context context){
        Toast.makeText(context, "登录成功啦!", Toast.LENGTH_SHORT).show();
    }
    public void loginFailure(Context context){
        Toast.makeText(context, "登录失败。", Toast.LENGTH_SHORT).show();
    }
}

好了,一个view层已经完成,下面来说model层,主要是对数据的请求,比如获取数据库中的数据,网络请求等:

这里我们假定进行网路请求,一个LoginModel,有一个返回结果的回调接口,具体模拟代码如下:

<pre style="font-family: 宋体; font-size: 15pt; background-color: rgb(255, 255, 255);"><pre name="code" class="java">public class LoginModel implements ILoginModel {
    @Override
    public void login(final String username, final String password, final ResultCallBack callBack) {
        // 模拟子线程的耗时操作,例如网路请求,这里我们使用异步请求
        new MyAsyncTask(callBack).execute(username, password);
    }

    private class MyAsyncTask extends AsyncTask<String, Void, Boolean>{

        ResultCallBack mCallBack;

        public MyAsyncTask(ResultCallBack callBack){
            this.mCallBack = callBack;
        }

        @Override
        protected Boolean doInBackground(String... params) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (params[0].equals("hjl") && params[1].equals("123456")){
                return true;
            } else {
                return false;
            }
        }

        @Override
        protected void onPostExecute(Boolean aBoolean) {
            if (aBoolean){
                mCallBack.success();
            } else {
                mCallBack.failure();
            }
        }
    }
}


最后实现controller层:

public class LoginController implements View.OnClickListener{

    private LoginView mLoginView;
    private MVCLoginActivity mContext;
    private ILoginModel mLoginModel;

    public LoginController(LoginView loginView, MVCLoginActivity context){
        this.mLoginView = loginView;
        this.mContext = context;
        mLoginModel = new LoginModel();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_login:
                final String username = mLoginView.getUserName();
                final String password = mLoginView.getPassword();
                if (TextUtils.isEmpty(username)){
                    mLoginView.userNameError(mContext);
                    break;
                }
                if (TextUtils.isEmpty(password)){
                    mLoginView.passWordError(mContext);
                    break;
                }
                // 调用model层进行网络请求
                mLoginModel.login(username, password, new ResultCallBack() {
                    @Override
                    public void success() {
                        mLoginView.loginSuccess(mContext);
                        mContext.finish();
                    }

                    @Override
                    public void failure() {
                        mLoginView.loginFailure(mContext);
                    }
                });
                break;
        }
    }
}

这样MVC框架就完成了,在Activity中展示:

public class MVCLoginActivity extends AppCompatActivity {

    private LoginView mLoginView = null;
    private LoginController mLoginController;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mvc_activity_login);
        // 控件的绑定
        mLoginView = (LoginView) findViewById(R.id.login_view);
        mLoginView.initModule();
        mLoginController = new LoginController(mLoginView, this);
        // 事件的监听
        mLoginView.setListeners(mLoginController);
    }

}

一个相对复杂的登录操作,在我们的Activity中只有简单的几行代码,具体的逻辑全都交给MVC,这里我们的思想是Activity不属于view层,而只供展示以及一些简单逻辑的处理,我们把MVC层全部单独为几个类,让Activity中仅仅几行代码,而且整体的代码结构相当的清晰!总结:对于控件的绑定等相关操作逻辑我们写在view层中,对于数据的获取(读取数据库,获取网络数据)我们写在model中,对于代码的所有逻辑(点击事件的处理,相关事件)等我们写在controller层中。

下一项我们来介绍MVP模式,个人感觉这个模式更好理解,弊端在文章开头已经说了。

之前看过大神分析过MVP模式,其实我第一次接触这种模式是我刚工作不久,公司项目里用到。当时因为基础不大好,总感觉超级麻烦,又是这么多类,这么多接口的,直接写在Activity中多省事。后来代码写的多一点了,就发现如果全都写在Activity中维护起来相当困难,有时候代码量多了,可能自己都看不懂自己写的代码了,也渐渐理解了设计模式的好处。

我们还是以这个登录需求为例,用MVP模式写一遍,体会一下。model层还是进行实体模型和业务逻辑,view层这里我们直接使用Activity,就是绑定控件等操作放在Activity中,不再多加一个类,presenter层负责处理model和view之间的交互。

首先还是写view层接口ILoginView,这里我们需要把所有需要的条件考虑到:

public interface ILoginView {
    String getUsername();
    String getPassword();
    void userError(Context context);
    void passwordError(Context context);
    void loginSuccess(Context context);
    void loginFailure(Context context);
}

接下来是model层,模拟网络请求

public class LoginModel implements ILoginModel {
    @Override
    public void login(final String username, final String password, final ResultCallBack callBack) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (username.equals("hjl") && password.equals("123456")) {
                    callBack.success();
                } else {
                    callBack.failure();
                }
            }
        }).start();
    }
}

最后在Activity中实现:

public class MVPLoginActivity extends AppCompatActivity implements View.OnClickListener, ILoginView {

    private EditText mUsername;
    private EditText mPassword;
    private Button mLoginBtn;
    private LoginPresenter mLoginPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mvc_activity_login);
        mLoginPresenter = new LoginPresenter(this);
        initView();
    }

    private void initView() {
        mUsername = (EditText) findViewById(R.id.et_username);
        mPassword = (EditText) findViewById(R.id.et_password);
        mLoginBtn = (Button) findViewById(R.id.btn_login);
        mLoginBtn.setOnClickListener(this);
    }

    @Override
    public String getUsername() {
        return mUsername.getText().toString().trim();
    }

    @Override
    public String getPassword() {
        return mPassword.getText().toString().trim();
    }

    @Override
    public void loginSuccess() {
        Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
        finish();
    }

    @Override
    public void loginFailure() {
        Toast.makeText(this, "用户名或密码错误", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_login:
                if (TextUtils.isEmpty(getUsername())) {
                    Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show();
                    break;
                }
                if (TextUtils.isEmpty(getPassword())) {
                    Toast.makeText(this, "密码不能为空", Toast.LENGTH_SHORT).show();
                    break;
                }
                mLoginPresenter.login();
                break;
        }
    }
}

以上就是android中的两种设计模式,不知道自己写的是否标准,但是感觉这样写已经达到了代码结构的清晰。其中MVC是借鉴极光推送im的demo,从中学习,而且感觉他写的这种方法是在很棒。第二种是项目中用到的,也很简单清晰。

以上所说的demo下载点击打开链接

时间: 2024-10-09 20:54:06

浅谈Android中的MVC与MVP模式的相关文章

浅谈android中的mvc模式

mvc是model.view.controller的缩写.android 鼓励弱耦合和组件的重用,android 中mvc的具体体现如下: 模型(model):是应用程序的主题部分,所有的业务逻辑都应在该层(对数据库的操作.对网络等的操作都应该在model里面处理,当然对计算等操作也是必须放在该层的). 视图层(view):是应用程序中负责生成用户界面的部分.也是整个mvc架构中用户唯一可以看到的一层,接收用户的输入,显示用户的处理结果.一般用xml文件进行界面的描述,使用的时候可以非常方便的引

浅谈android中的ListView合集系列之解决ScrollView和ListView嵌套冲突(一)

相信大家都已经可以熟练使用ListView和GridView,大神们估计都在使用RecyclerView了.如果还在使用ListView,你肯定有这样的一个深刻的感受,那就是在做一个APP的时候使用ListView和GridView很频繁,并且经常会遇到一个页面中除了有ListView或GridView可能还有一些其他的内容,但是可能内容很多,你第一时间就会想到让它整体滑动即可,那就是在总的布局外面包裹一个ScrollView.也就是出现了ScrollView中嵌套一个ListView的场景,或

浅谈Android中的MVP

转载请标明出处: http://blog.csdn.net/hai_qing_xu_kong/article/details/51745798 本文出自:[顾林海的博客] 前言 为什么使用MVP,网上有很多说法,最主要就是减轻了Activity的责任,相比于MVC中的Activity承担的责任太多,因此有必要讲讲MVP. MVP入门 在MVC框架中,View是可以直接读取Model模型中的数据的,Model模型数据发生改变是会通知View数据显示发生相应的改变.而在MVP中Model和View之

浅谈android中手机联系人字母索引表的实现

实际上字母索引表的效果,可以说在现在的众多APP中使用的非常流行,比如支付宝,微信中的联系人,还有购物,买票的APP中选择全国城市,切换城市的时候,这时候的城市也就是按照一个字母索引的顺序来显示,看起来是很方便的.其实这种字母索引表的效果最开始是出现在微信的联系人中.因为觉得这种效果功能在今后的项目中可以说是非常常见,可能会用的上,所以准备来波博客讲述一下实现的原理,一来方便以后自己复习,二来如果能够帮助一些android路上奋斗小伙伴也是蛮有意义的. 下面我们先来看下效果图, 看完效果图后我们

浅谈android中图片处理之图形变换特效Matrix(四)

今天,我们就来谈下android中图片的变形的特效,在上讲博客中我们谈到android中图片中的色彩特效来实现的.改变它的颜色主要通过ColorMatrix类来实现. 现在今天所讲的图片变形的特效主要就是通过Matrix类来实现,我们通过上篇博客知道,改变色彩特效,主要是通过ColorMatrxi矩阵的系数,以及每个像素点上所对应的颜色偏移量.而今天的图形变换与那个也是非常的类似.它是一个3*3矩阵,而颜色矩阵则是一个4*5的矩阵.在这个3*3矩阵中则表述出了每个像素点的XY坐标信息.然后通过修

浅谈android中仅仅使用一个TextView实现高仿京东,淘宝各种倒计时

今天给大家带来的是仅仅使用一个TextView实现一个高仿京东.淘宝.唯品会等各种电商APP的活动倒计时.最近公司一直加班也没来得及时间去整理,今天难得休息想把这个分享给大家,只求共同学习,以及自己后续的复习.为什么会想到使用一个TextView来实现呢?因为最近公司在做一些优化的工作,其中就有一个倒计时样式,原来开发的这个控件的同事使用了多个TextView拼接在一起的,实现的代码冗余比较大,故此项目经理就说:小宏这个就交给你来优化了,并且还要保证有一定的扩展性,当时就懵逼了.不知道从何处开始

浅谈android中的异步加载一

1.为什么需要异步加载. 因为我们都知道在Android中的是单线程模型,不允许其他的子线程来更新UI,只允许UI线程(主线程更新UI),否则会多个线程都去更新UI会造成UI的一个混乱有些耗时的操纵(例如网络请求等),如果直接放到主线程中去请求的话则会造成主线程阻塞,而我们系统有规定的响应时间,当响应的时间超过了了阻塞的时间就会造成"Application No Response",也就是我们熟知的ANR错误解决上述问题的时候:我们一般使用的是线程或者线程池+Handler机制如果线程

浅谈android中只使用一个TextView实现高仿京东,淘宝各种倒计时

今天给大家带来的是只使用一个TextView实现一个高仿京东.淘宝.唯品会等各种电商APP的活动倒计时.近期公司一直加班也没来得及时间去整理,今天难得歇息想把这个分享给大家.只求共同学习,以及自己兴许的复习. 为什么会想到使用一个TextView来实现呢?由于近期公司在做一些优化的工作,当中就有一个倒计时样式,原来开发的这个控件的同事使用了多个TextView拼接在一起的.实现的代码冗余比較大.故此项目经理就说:小宏这个就交给你来优化了.而且还要保证有一定的扩展性,当时就懵逼了.不知道从何处開始

Android中的MVC,MVP和MVVM

韩梦飞沙  韩亚飞  [email protected]  yue31313  han_meng_fei_sha MVC,MVP,MVVM的区别 #MVC 软件可以分为三部分 视图(View):用户界面 控制器(Controller):业务逻辑 模型(Model):数据保存 各部分之间的通信方式如下: View传送指令到Controller Controller完成业务逻辑后,要求Model改变状态 Model将新的数据发送到View,用户得到反馈 Tips:所有的通信都是单向的. #互动模式