MVC和MVP使用指南

2018-08-16  本文已影响23人  kim_liu

前面有写过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();
    }
}

上一篇下一篇

猜你喜欢

热点阅读