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