MVP框架学习笔记
一.什么是MVP框架
MVP的思想是将activity作为view层,只负责与XML的渲染和监听事件,具体处理数据逻辑放到一个新定义的Present层。减少了activity负责的事情。并且可以强迫开发者养成分模块功能开发的思想。开发前设计好功能模块,而不是像以前一样写流水账一样写代码。从头写到尾。可以更好的降低软件的耦合性,方便代码的复用和工程开发。
(1)Presenter – 交互中间人:Presenter主要作为沟通View与Model的桥梁,它从Model层检索数据后,返回给View层,使得View与Model之间没有耦合,也将业务逻辑从View角色上抽离出来。
(2)View – 用户界面:View通常是指Activity、Fragment或者某个View控件,它含有一个Presenter成员变量。通常View需要实现一个逻辑接口,将View上的操作转交给Presenter进行实现,最后,Presenter 调用View逻辑接口将结果返回给View元素。
(3)Model – 数据的存取:Model 角色主要是提供数据的存取功能。Presenter 需要通过Model层存储、获取数据,Model就像一个数据仓库。更直白的说,Model是封装了数据库DAO或者网络获取数据的角色,或者两种数据方式获取的集合。
二.MVP框架理解
我们在日常开发中,很多网络请求是重复的,比如加入购物车,这个接口会在商品详情中出现,也可能会在商品列表中出现, 在购物车的数量更改上也可能用到它,如果不复用他,我们就需要在每个界面的model层中去复制粘贴他,但是这样又远离的mvp的中心思想,mvp就是想让你在最大程度上复用,减少无用代码,那么这样的接口我们应该怎样处理呢。对于这个问题有以下几个思路解决:
1.我们可以让一个p层去持有多个model,通过这样的方式来复用model;
2.我们可以让一个view持有多个p,每个p去调用不同的model分别处理不同的事务;
3. 我们可以将model模块进行拆分,将大量复用的model单独拆分出来,让这个model可以去被其他model调用,这样也实现了最大程度上的复用;
三.MVP框架存在的问题
尽管已经有了大量的应用,但不可否认该模式的还是存在一些问题,这些问题在携程的使用过程中也得到了体现。比如,上下文丢失问题,生命周期问题,内存泄露问题以及大量的自定义接口,回调链变长等问题。可以归纳为:
1.业务复杂时,可能使得Activity变成更加复杂,比如要实现N个IView,然后写更多个模版方法。
2.业务复杂时,各个角色之间通信会变得很冗长和复杂,回调链过长。
3.Presenter处理业务,让业务变得很分散,不能全局掌握业务,很难去回答某个业务究竟是在哪里处理的。
4.用Presenter替代Controller是一个危险的做法,可能出现内存泄漏,生命周期不同步,上下文丢失等问题。
四.MVP框架实例参照
项目目录:
LoginBean文件:
package com.mvptest.mvp_demo.bean;
/**
* Author:XuPF
* Time:2018/8/14 14:36
* Description:This is LoginBean
*/
public class LoginBean {
private String userName;
private String userPwd;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
public LoginBean(String userName, String userPwd) {
this.userName = userName;
this.userPwd = userPwd;
}
}
LoginModel文件:
package com.mvptest.mvp_demo.model;
import android.text.TextUtils;
import com.mvptest.mvp_demo.bean.LoginBean;
import com.mvptest.mvp_demo.netWork.NetTask;
import com.mvptest.mvp_demo.netWork.RequestStatus;
/**
* Author:XuPF
* Time:2018/8/14 14:53
* Description:This is LoginModel
*/
public class LoginModel implements NetTask {
@Override
public void exec(LoginBean loginBean, RequestStatus requestStatus) {
String name = loginBean.getUserName();
String pwd = loginBean.getUserPwd();
if (name == null && TextUtils.isEmpty(name)) {
requestStatus.onError();
return;
}
if (pwd == null && TextUtils.isEmpty(pwd)) {
requestStatus.onError();
return;
}
//这里处理和网络交互的逻辑
requestStatus.onStart();
//模拟请求网络
if (!name.equals("1")) {
requestStatus.onError();
return;
} else {
if (!pwd.equals("1")) {
requestStatus.onError();
return;
} else {
requestStatus.onSuccess("恭喜你登录成功");
}
}
}
}
LoginPresenter文件:
package com.mvptest.mvp_demo.presenter;
import com.mvptest.mvp_demo.view.LoginBaseInterface;
import com.mvptest.mvp_demo.bean.LoginBean;
import com.mvptest.mvp_demo.netWork.NetTask;
import com.mvptest.mvp_demo.netWork.RequestStatus;
/**
* Author:XuPF
* Time:2018/8/14 14:48
* Description:This is LoginPresenter
* LoginPresenter 实现约定接口中的presenter接口和请求网络状态的接口
*/
public class LoginPresenter implements LoginBaseInterface.LoginPresenterInterface,RequestStatus {
private NetTask<LoginBean> netTask;
private LoginBaseInterface.LoginViewInterface viewInterface;
public LoginPresenter(NetTask<LoginBean> netTask, LoginBaseInterface.LoginViewInterface viewInterface) {
this.netTask = netTask;
this.viewInterface = viewInterface;
}
@Override
public void requestToLogin(LoginBean loginBean) {
netTask.exec(loginBean,this);
}
@Override
public void onStart() {
viewInterface.showRequestNetDialog();
}
@Override
public void onSuccess(String str) {
viewInterface.cancelRequestNetDialog();
viewInterface.LoginSuccess(str);
}
@Override
public void onError() {
viewInterface.cancelRequestNetDialog();
viewInterface.LoginUnSuccess();
}
}
LoginActivity文件:
package com.mvptest.mvp_demo.view;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.mvptest.mvp_demo.R;
import com.mvptest.mvp_demo.bean.LoginBean;
import com.mvptest.mvp_demo.model.LoginModel;
import com.mvptest.mvp_demo.presenter.LoginPresenter;
public class LoginActivity extends AppCompatActivity implements LoginBaseInterface.LoginViewInterface, View.OnClickListener {
private ProgressBar mLoginPb;
/**
* 手机号
*/
private EditText mUserMobileEt;
/**
* 密码
*/
private EditText mUserPwdEt;
/**
* 登 录
*/
private TextView mLoginConfirmTv;
private LoginPresenter loginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
LoginModel loginModel = new LoginModel();
loginPresenter = new LoginPresenter(loginModel,this);
}
@Override
public void showRequestNetDialog() {
if (!mLoginPb.isShown()) {
mLoginPb.setVisibility(View.VISIBLE);
}
}
@Override
public void cancelRequestNetDialog() {
if (mLoginPb.isShown()) {
mLoginPb.setVisibility(View.INVISIBLE);
}
}
@Override
public void LoginSuccess(Object o) {
if (mLoginPb.isShown()) {
mLoginPb.setVisibility(View.INVISIBLE);
}
Toast.makeText(getApplicationContext(), (String)o, Toast.LENGTH_LONG).show();
Intent intent = new Intent(LoginActivity.this,FirstActivity.class);
startActivity(intent);
}
@Override
public void LoginUnSuccess() {
if (mLoginPb.isShown()) {
mLoginPb.setVisibility(View.INVISIBLE);
}
Toast.makeText(getApplicationContext(), "登录失败", Toast.LENGTH_LONG).show();
}
private void initView() {
mLoginPb = (ProgressBar) findViewById(R.id.login_pb);
mUserMobileEt = (EditText) findViewById(R.id.user_mobile_et);
mUserPwdEt = (EditText) findViewById(R.id.user_pwd_et);
mLoginConfirmTv = (TextView) findViewById(R.id.login_confirm_tv);
mLoginConfirmTv.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
default:
break;
case R.id.login_confirm_tv:
loginPresenter.requestToLogin(new LoginBean(mUserMobileEt.getText().toString().trim(),mUserPwdEt.getText().toString().trim()));
break;
}
}
}
LoginBaseInterface文件:
package com.mvptest.mvp_demo.view;
/**
* Author:XuPF
* Time:2018/8/14 14:38
* Description:This is LoginBaseInterface
*/
public class LoginBaseInterface {
public interface LoginPresenterInterface<T>{
void requestToLogin(T t);
}
public interface LoginViewInterface<T>{
void showRequestNetDialog();//展示请求网络的dialog
void cancelRequestNetDialog();//finish掉dialog
void LoginSuccess(T t);//登录成功
void LoginUnSuccess();//登录不成功
}
}
FirstActivity文件:
package com.mvptest.mvp_demo.view;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import com.mvptest.mvp_demo.R;
import com.mvptest.mvp_demo.model.LoginModel;
import com.mvptest.mvp_demo.presenter.LoginPresenter;
public class FirstActivity extends AppCompatActivity implements LoginBaseInterface.LoginViewInterface, View.OnClickListener {
private TextView mFirstView;
@Override
public void onClick(View view) {
}
@Override
public void showRequestNetDialog() {
}
@Override
public void cancelRequestNetDialog() {
}
@Override
public void LoginSuccess(Object o) {
}
@Override
public void LoginUnSuccess() {
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView(){
mFirstView = (TextView) findViewById(R.id.FirstView);
}
}