Android框架模式MVP总结和示例程序设计

54 篇文章 0 订阅

Android框架模式MVP总结

         Android框架模式MVC和MVP,之前已经是有相关总结,但是在开发中用得很少,也没怎么注意,很多代码都是随意写的,但是现在开发要求按照MVP的设计模式,所有我想对MVP框架设计做一个总结,并设计一个Demo程序帮助大家更好的理解MVP,理顺MVP的设计思路,重要的是学会使用MVP。 
         这里我也是不想讲什么MVC模式跟MVP模式的比较这一方面的知识了,现在一旦使用MVP就很少人使用MVC模式了。 
         以前一个关于MVP和MVC框架模式相关知识的总结: 
http://blog.csdn.net/wenzhi20102321/article/details/53302453

一.MVP框架设计模式基本认识

(一)基本概念

         MVP是模型(Model)、视图(View)、主持人(Presenter)的缩写,分别代表项目中3个不同的模块。 

模型(Model):负责处理数据的加载或者存储,比如从网络或本地数据库获取数据等;

视图(View):负责界面数据的展示,与用户进行交互;

主持人(Presenter):相当于协调者,是模型与视图之间的桥梁,将模型与视图分离开来。

         MPV 是从经典的MVC模式演变过来的,其基本思路都是相通的。其中M是model模型,提供业务数据;P和MVC中的C担当的角色相似,是Presenter主持人,进行逻辑处理。V是View视图,显示页面操作。

MVP与MVC有着一个重大的区别:

         在MVP中View并不直接使用Model,它们之间的通信是通过Presenter 来进行的,所有的交互都发生在Presenter这个类内部,在代码中可以发现Presenter类既有View对象,又有Model对象,但是在Activity中是没有Model对象的,是使用Presenter对象来调用Model对象;Activity是要有View对象和Presenter对象的,Presenter对象怎么来呢,这个是要在构造方法中去创建。View对象怎么来呢,其实是Activity实现这个View,这个Activity就相对于这个View对象,并且需要重写View接口的方法!而且还有一个重要的就是要用这个Presenter来绑定Activity(其实是为了绑定View接口的方法)。这样在Presenter用model处理完数据后,Presenter就会调用View接口的方法,实现页面的操作。  
         上面这一段话也是MVP框架模式的重点理论,需要理解透彻。你也可以从我的代码中细细的体会,一定要搞清楚它们的关系! 
   
         如下图所示,View与Model并不直接交互,而是使用Presenter作为View与Model之间的桥梁。其中Presenter中同时持有Viwe层以及Model层的Interface的引用,而View层持有Presenter层Interface的引用。当View层某个界面需要展示某些数据的时候,首先会调用Presenter层的某个接口,然后Presenter层会调用Model层请求数据,当Model层数据加载成功之后会调用Presenter层的回调方法通知Presenter层数据加载完毕,最后Presenter层再调用View层的接口将加载后的数据展示给用户。这就是MVP模式的整个核心过程。 
s

         这样分层的好处就是大大减少了Model与View层之间的耦合度。一方面可以使得View层和Model层单独开发与测试,互不依赖。另一方面Model层可以封装复用,可以极大的减少代码量。当然,MVP还有其他的一些优点,这里不再赘述。

(二)开发中MVP框架模式的设计

1.一般MVP设计都是都是新建一个mvp的包名,里面分别在建model、view、presenter包名,mvp包名和页面的包名ui的activity和fragment是分开的。

如图所示: 
s2 
         虽然MVP是针对页面的逻辑,但是mvp放到activity包名下就显得很难看。

注意:之前我也是有这样一个疑问:view和ui这两个不是都是放视图的包吗?

         其实是这样的:MVP中的View的包下放的并不是activity这样的视图类,而是activity视图类的操作,比如这个登录的activity下,会有获得用户的账号,密码的需要,也有点击登录的需要等等,这就需要定义这几个操作的方法,其实这里view包下定义的是接口类,里面的方法都是抽象方法,定义这个页面需要的操作,具体页面内容的实现还是要在Activity中来!

2.mvp包下的文件设计

(1)model包名下的类

         设计数据处理的逻辑,这里一般还设计一个内部接口类,让presenter对象可以设置监听并得到数据。因为好多数据处理都是需要子线程的,不能马上就返回数据。

(2)view包名下的类

         设计视图中需要的逻辑,都是接口方法,该类也是接口类。这个接口类也是需要固定的Activity页面来实现,并重写里面的方法,在方法里面写入页面的操作,这些重写方法方法能否得到回调都是Presenter对象来控制的,一般都是数据或逻辑处理完后再判断相应的方法回调。

(3)presenter包名下的类

         设计activity和model的交互,既要有View对象,也要有model对象。

         Activity中把数据相关的逻辑操作都扔给了Presenter去做,View只负责处理与用户界面操作。而Presenter调用Model处理完数据之后,再通过View接口方法更新View显示的信息。

二.下面看下MVP模式在具体项目中的使用。

下面是设计一个登录页面的程序,向大家详细介绍设计过程。 
界面如下: 
s3

点击登录并验证成功后跳转到用户界面。

(一)详细设计过程和思路

1.先写布局页面,这个应该是最简单的吧,两个EditText和一个按钮就可以。

2.设计用户的基类User,设置用户名和密码的get和set方法。

3.设计mvp中的View接口类LoginView,接口里面定义方法:获得用户的账号、获得用户的密码、登录、显示网络异常、登录验证错误这五个方法。

代码:

/**
 * mvp中的View的定义
 * 用户登录界面用户的操作行为的定义
 */
public interface LoginView {


    String getAccount();//获取用户的账号,返回账号

    String getPassword();//获取用户的莫玛,返回密码

    void loginSuccess(User user);//登录的实现,需要传入用户对象

    void showNetworkError();//显示网络异常

    void showVerifyFailed();//信息验证失败,账号或密码有误
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

4.设计mvp中的model类LoginModel,这个类需要验证用户的账号和密码是否正确。并创建一个内部接口,让数据处理完成后返回时间,因为一般网络数据都是在子线程中完成,不能马上返回数据。

代码:

/**
 * MVP中的model数据处理类
 * 这里处理登录时的数据
 */
public class LoginModel {

    /**
     * 处理登录业务并返回结果
     */
    public void login(String name,String password,OnLoginResultListener onLoginResultListener){
        //一般登录都是请求服务器,验证
        //这里就简单一点,大家别介意
        if ("liwen".equals(name)&&"123456".equals(password)){
            onLoginResultListener.loginSuccess(new User(name,password));//登录成功,给他返回用户对象
        }else {
            onLoginResultListener.loginFailure();//登录失败
        }

    }


    //回调接口
    public interface OnLoginResultListener {

        void loginSuccess(User user);//登录成功后回调的方法,返回User对象

        void loginFailure();//登录失败后回掉的方法

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

5.设计mvp中的Presenter类LoginPresenter,实现View和Model的交换,重点理解

/**
 * mvp中Presenter中的设计
 * 也是比较难,需要重点理解的一个
 * presenter是主持人的意思,view和model的中间者
 * 需要同时要有View的对象和Model的对象!一般做法是:在构造方法中创建model对象,并创建一个方法绑定View接口
 * 这里可以发现数据处理后或者逻辑判断完后都是给mvp中的View对象来做操作的!
 */
public class LoginPresenter {

    /**
     * 登录业务实现者,数据处理的操作者
     */
    private LoginModel mLoginModel;

    /**
     * 在构造方法中实例化model对象
     */
    public LoginPresenter() {
        mLoginModel = new LoginModel();

    }


    //视图接口对象
    private LoginView mLoginView;

    /**
     * 绑定View 的方法
     *
     * @param loginView
     */
    public void bind(MyActivity loginView) {
        mLoginView = loginView;
    }

    /**
     * 登录业务
     */
    public void login() {
        String account = mLoginView.getAccount();
        String password = mLoginView.getPassword();
        Log.e("TAG", "account:" + account + ",password" + password);
        if (checkParameter(account, password)) {
            doSomePrepare();
            //登录 ,需要处理数据,所有要在model中执行
            mLoginModel.login(account, password, new LoginModel.OnLoginResultListener() {
                //登录成功的回调方法
                @Override
                public void loginSuccess(User user) {
                    mLoginView.loginSuccess(user);   //在给视图页面返回User对象
                }

                //登录失败的回调方法
                @Override
                public void loginFailure() {
                    mLoginView.showVerifyFailed();//在给视图页面返回验证失败的结果
                }
            });


        }
    }


    /**
     * 做一些准备
     */
    private void doSomePrepare() {
        //这里可以设置按钮不可点击!否则一直点击登录也是不好
    }

    /**
     * 检测参数是否是否为空~~~
     *
     * @param account
     * @param password
     * @return
     */
    private boolean checkParameter(String account, String password) {
        if (TextUtils.isEmpty(account) | TextUtils.isEmpty(password)) {
            mLoginView.showVerifyFailed();//提示错误
            return false;
        } else if (!checkNetwork()) {
            mLoginView.showNetworkError();//提示网络错误
            return false;
        }
        return true;
    }

    /**
     * 检测网络是否可用
     */
    public boolean checkNetwork() {
        return true;//先显示可以联网,实际中要用代码判断
    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98

         上面有些方法是可以不写的,比如检查网络或做一些准备,但是实际程序中,是要做很多判断的,这里就随便啰嗦几句。

6.下面就是Activity了,也是比较难一点的,需要重点理解

/**
 * 登录程序示例的Activity
 * 这里需要创建presenter对象,presenter对象中是有view对象和model对象的!
 */
public class MyActivity extends Activity implements LoginView, View.OnClickListener {

    private EditText et_name;
    private EditText et_password;
    private Button btn_logon;

    private LoginPresenter loginPresenter;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        initView();
    }

    /**
     * 初始化数据
     */
    private void initView() {
        et_name = (EditText) findViewById(R.id.et_name);
        et_password = (EditText) findViewById(R.id.et_password);
        btn_logon = (Button) findViewById(R.id.btn_login);
        btn_logon.setOnClickListener(this);
        loginPresenter = new LoginPresenter();

        loginPresenter.bind(this);//绑定View和Presenter,因为这个Activity已经实现了接口,已经包含了View对象
    }

    /**
     * 登录按钮的监听方法
     * 这里要做后台数据的处理,需要用到Presenter
     */
    @Override
    public void onClick(View v) {
        loginPresenter.login();
    }

    /**
     * 下面五个方法都是实现LoginView后要是实现的方法
     */

    @Override
    public String getAccount() {
        return et_name.getText().toString();
    }

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

    @Override
    public void loginSuccess(User user) {
        //登录成功后,一般是实现页面的跳转
        Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();

    }

    @Override
    public void showNetworkError() {
        Toast.makeText(this, "当前网络不可用", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showVerifyFailed() {
        Toast.makeText(this, "输入的用户名或密码有误", Toast.LENGTH_SHORT).show();
    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

         上面可以看到在初始化时就创建loginPresenter对象,而loginPresenter的构造方法中也是创建了loginModel对象,Activity实现了LoginView,就相当于有了LoginView对象,这是只需要用loginPresenter绑定LoginView,这时MVP的model、view、presenter三者都已经实例化,并关联在一起了。 
         上面语句loginPresenter绑定LoginView的是:loginPresenter.bind(this);绑定Avtivity,也是绑定View!loginPresenter中调用LoginView的方法都是在Activity中执行的。 
程序运行后的显示: 
s5

下面是源码的下载地址: 
http://download.csdn.net/detail/wenzhi20102321/9803842

(二)MVP的理解和其他知识

         其实上面已经是一个MVP框架模式的标准程序,但是算是最简单哪种,一般的程序还要做更多的判断。比如,判断账号,密码为空等等。 
         在实际使用MVP模式中,你不只是要创建一个View、Presenter或Model,比较好的做法就是创建三个Base类(BaseView是接口),让每一个View、Pressenter或Model去继承这个Base类,而这个Base类做一些共同的操作,比如:BasePresenter就可以写绑定View的方法,因为每一个Presenter都是必须要绑定View的;而BaseView可以做一些每个页面都需要的方法:显示动画,隐藏动画,显示网络异常的方法等等。总之根据程序的实际需求来设计就好。

         也有人会想问使用MVP是不是很麻烦,如果使用MVP不是每个页面多要设计model、presenter和view,这要做多少工作!

这里我也简单说一下我的理解:

         其实使用MVP就是要让程序降低耦合度,让逻辑更加清楚;也不是所有的Activity页面都是要使用MVP,一般的涉及到较多数据处理,比如登录界面、注册界面是需要MVP框架模式的,而那些简单页面,比如只是显示简单数据或试图或显示某一个控件的Activity是不需要使用MVP来完成的,按照正常逻辑设计就可以了。 
         MVP到这里介绍完了,我想很多人应该是可以理解的吧,不理解的话可以下载源码慢慢体会下,同时写个注册页面实践一些,就会有清楚的思路了。也可以发表留言讨论。

共勉:活在当下

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值