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

来源:互联网 发布:列数据的句子 编辑:程序博客网 时间:2024/06/06 07:16

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();//信息验证失败,账号或密码有误}

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();//登录失败后回掉的方法    }

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;//先显示可以联网,实际中要用代码判断    }}

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

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();    }}

         上面可以看到在初始化时就创建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到这里介绍完了,我想很多人应该是可以理解的吧,不理解的话可以下载源码慢慢体会下,同时写个注册页面实践一些,就会有清楚的思路了。也可以发表留言讨论。

共勉:活在当下

3 0
原创粉丝点击