美文网首页
MVC和MVP使用指南

MVC和MVP使用指南

作者: kim_liu | 来源:发表于2018-08-16 16:33 被阅读23次

    前面有写过MVP,但写的只是一个思路,好记性不如烂笔头,现在年纪大了是真的记性越来越差,以往在项目中用过的架构,比如MVC,个人认为我自己搭建的改良版MVC比MVP要好用,但MVP也是要记录下来的。后续还会添加MVVM,听说MVP+MVVM很好用,后面也打算研究一下。

    这篇博客只介绍使用,为了理清思路。

    首先介绍我自己一直以来使用的MVC模式架构。

    MVC

    不管是MVP还是MVC,作用都是把网络请求和界面显示的逻辑分开,M:model层,所有的实体类都由该层管理。 V:view层,所有的界面显示逻辑在这一层。C:controller 所有的网络请求在这一层。MVC的关键是在c层, 怎么来编写Controller呢?

    1.BaseController

    作为所有Controller的基类,其中需要有一个handleMessage(),该方法用来处理网络请求,由所有子类重写,因为每一个子类网络请求的逻辑都不同,因此该方法需要做成一个抽象方法,该方法的参数可见代码中注释。另外,需要使用接口回调的方式把网络请求的结果传递出去。那么写出来的BaseController代码如下。

    public abstract class BaseController {
    
        //定义一个Listener,用来传递网络请求的数据
        protected IModeChangeListener mListener;
        protected Context mContext;
    
       //定义一个方法把Listener set到Controller中,方便使用
        public void setIModeChangeListener(IModeChangeListener listener) {
            mListener=listener;
        }
    
        public BaseController(Context c) {
            mContext=c;
        }
    
        /**
         * 子类处理具体的需求的业务代码
             @param action 标识,用来区分是哪个网络请求
             @param values  网络请求所需要的参数
         */
        public abstract void handleMessage(int action,Object... values);
    }
    
    
    2.IModeChangeListener

    网络请求状态改变接口,在网络请求状态改变时调用,在其中有两个方法:onModeChanged()和onError() 分别在请求成功和请求失败是调用。

    public interface IModeChangeListener {
    
        /**
         * 
         * @param action 返回处理不同UI的action 
            @param 请求完返回的数据
         */
          //  onModeChanged 请求成功时调用,跟UI说界面需要修改 
         void onModeChanged(int action,Object... values);
         void onError(int action,Object... values);
    }
    
    3.进行一次网络请求

    例如:在MainActivity中做一次数据请求。
    3.1 MainActivity必须继承IModeChangeListener
    3.2 创建一个MainController,专门为MainActivity服务。
    3.3 在MainActivity中,new一个MainController对象,并且绑定IModeChangeListener。
    3.4 调用MainController中的handleMessge(action, values)发送网络请求,指明action和需要传递的参数。
    3.5 在MainController的HandlerMessage(action,values)中接收传递过来的参数,根据action判断是什么请求,并作出相应的动作。
    3.6 在请求结束的地方调用onModeChanged()和onError()。每一个返回的动作也都有自己的action,在页面中进行判断是哪一个返回,从而作出相应的数据显示。
    代码如下:步骤已在代码中注释。

    BaseController:
    public abstract class BaseController {
        
        protected Context mContext;
        public BaseController(Context context) {
            this.mContext = context;
        }
    
        //在父类中进行接口的绑定,在子类中就可以直接拿来用
        protected IModelChangeListener iModelChangeLIstener;
        public void setiModelChangeLIstener(IModelChangeListener iModelChangeLIstener){
            this.iModelChangeLIstener = iModelChangeLIstener;
        }
    
        /**
         * 请求网络的方法,需要子类进行重写
         * @param action 动作,用来区分是哪一个网络请求
         * @param values 参数
         */
        public abstract void handleMessage(int action,Object...values);
        
    }
    
    IModeChangeListener
    public interface IModeChangeListener {
    
    
        /**
         * 数据请求成功时调用
         * @param action 返回的action,用来确定是哪个返回
         * @param values 请求成功的数据
         */
        void onModeChange(int action,Object...values);
    
        /**
         * 数据请求失败时调用
         * @param action 同上
         * @param values 服务器返回的失败信息
         */
        void onError(int action,Object...values);
    }
    
    
    MainActivity
    public class MainActivity extends AppCompatActivity implements IModeChangeListener {
    //继承IModeChangeListener
    
        //定义一个action,一般写在全局的ConstantValue 文件中
        public final static  int LOGIN_ACTION = 0;
        private String json;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main4);
    
            loadData();
        }
    
        /**
         * 请求数据
         */
        private void loadData() {
    
            //创建MainController对象,并且绑定IModelChangeListener
            MainController mainController = new MainController(this);
            mainController.setIModeChangeLIstener(this);
    
            //创建参数
            String userName = "zhangsan";
            String passWord = "123456";
    
            //调用MainController中的handleMessage()发生网络请求 
            mainController.handleMessage(LOGIN_ACTION,userName,passWord);
    
        }
    
    
        @Override
        public void onModeChange(int action, Object... values) {
            //在这里接收MainController传递回来的信息
            switch (action){
                case MainController.RESPONSE_LOGIN_ACTION:
                    json = values[0]+"";//返回来的数据
                    break;
            }
    
        }
    
        @Override
        public void onError(int action, Object... values) {
            //接收传递回来的错误信息
            switch (action){
                case MainController.RESPONSE_LOGIN_ACTION:
                    String errorMsg = values[0]+"";
                    break;
            }
    
        }
    }
    
    MainController
    public class MainController extends BaseController {
    
        //定义一个返回的action
        public static final int RESPONSE_LOGIN_ACTION = 1000;
    
        public MainController(Context context) {
            super(context);
        }
    
        @Override
        public void handleMessage(int action, Object... values) {
            switch (action){
                case Main4Activity.LOGIN_ACTION:
                    login(values);
                    break;
            }
        }
       /**
         * 登录
         * @param values 传递过来的参数
         */
        private void login(Object[] values) {
            OkGo.<String>get(url)
                    .params("username",values[0]+"")
                    .params("password",values[1]+"")
                    .execute(new StringCallback() {
                        @Override
                        public void onSuccess(com.lzy.okgo.model.Response<String> response) {
                            //返回的json值
                            String json = response.body();
                            //将返回的json值传递回去
                            iModelChangeLIstener.onModeChange(RESPONSE_LOGIN_ACTION,json);
                        }
    
                        @Override
                        public void onError(com.lzy.okgo.model.Response<String> response) {
                            super.onError(response);
                            String errorMsg = response.body();
                            //传递错误信息
                           iModelChangeLIstener.onError(RESPONSE_LOGIN_ACTION,errorMsg+"");
                        }
                    });
        }
    }
    

    MVC的用法大致就是这样,实现了网络请求和显示界面逻辑的分离。

    MVP

    MVP和MVC不同,MVP分为三层,分别是Model、View、Presenter。其中Presenter是网络请求层。那么MVP怎么用的呢?通过一个登录的案例来用一下MVP吧。
    1.首先是页面显示逻辑。我们需要创建一个接口BaseView,该接口是所有页面显示逻辑类的父类,在其中编写所有页面都会有的显示逻辑,如Toast和Dialog。

    public interface BaseView {
        void showToast(String msg);
        void showDialog();
    }
    

    2.主页有两个显示逻辑,分别是登录成功和登录失败,编写接口MainView,继承BaseView,并在其中添加属于它自己的显示逻辑。

    public interface MainView extends BaseView {
         void loginSuccess();
         void loginFail();
    }
    

    3.数据请求的逻辑,这个逻辑由P层负责,创建一个接口BasePresenter,为其指定范型,这个范型就是该Presenter需要绑定的View的类型。

    public interface BasePresenter<T> {
        void attachView(T view);
        void detachView();
    }
    

    4.为BasePresenter创建一个实现类,该类真正实现了View的绑定和解绑。

    public class BasePresenterImpl<T extends BaseView> implements BasePresenter<T> {
    
        public T presentView;
    
        @Override
        public void attachView(T view) {
            this.presentView = view;
        }
    
        @Override
        public void detachView() {
            this.presentView = null;
        }
    }
    

    5.专门为主页创建一个接口,MainPresenter处理主页数据请求的逻辑,继承BasePresenter,传入的范型是MainView,父类中的attatchView()将MainPresenter和MainView绑定在一起。

    /**
     * Created by kimliu on 2018/8/3
     *主页处理逻辑的接口
     */
    public interface MainPresenter extends BasePresenter<MainView>{
    
        void login(String name,String pwd);
    }
    

    6.为MainPersenter创建实现类。具体逻辑写在其中

    /**
     * Created by kimliu on 2018/8/3
     * 主页处理逻辑接口的实现类,主页逻辑的真正实现在这里
     */
    public class MainPresentImpl extends BasePresenterImpl<MainView> implements MainPresenter {
        //绑定了MainView
        @Override
        public void login(String name,String pwd) {
            if(name.equals("zhangsan") && pwd.equals("123")){
                presentView.loginSuccess();
            }else{
                presentView.loginFail();
            }
        }
    }
    

    7.在MainActivity中创建一个MainPresentImpl对象,并且调用其中的login方法。这个与上面讲到的MVC一样,都是使用的接口回调来传递数据,上面的MVC是通过定义标识来区分是哪一个网络请求,MVP则是通过不同的类实现不同的接口来区分是哪一个网络请求

    public class MainActivity extends AppCompatActivity implements MainView{
    
        public MainPresentImpl mainPresent;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mainPresent = new MainPresentImpl();
            //绑定MainView
            mainPresent.attachView(this);
         //创建数据
            String username = "zhangsan";
            String pwd = "123456";
        //登录
           mainPresent.login(username,pwd);
    
        }
    
        @Override
        public void loginSuccess() {
            showToast("loginSuccess");
        }
    
        @Override
        public void loginFail() {
            showToast("loginFail");
    
        }
    
        @Override
        public void showToast(String msg) {
            Toast.makeText(this,msg+"",Toast.LENGTH_SHORT).show();
    
        }
    
        @Override
        public void showDialog() {
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            mainPresent.detachView();
        }
    }
    
    

    相关文章

      网友评论

          本文标题:MVC和MVP使用指南

          本文链接:https://www.haomeiwen.com/subject/cvswbftx.html