MVP框架搭建·源码
通过本文记录一下学习MVP三层架构的思想,并实现一个基础的MVP项目架构搭建过程,通过MVC架构设计一文了解到MVC存在内存泄漏的缺陷,而MVP通过弱应用可以很好的解决内存泄漏这个问题
本文通过用户登录案例实现MVP框架的搭建
MVP相对于MVC的区别在于,增加了Presenter协议层,通过Presenter协议层解耦了View层和Model层,MVP架构大致分为以下三种类型
- 1.P接收V层的事件分发给M层进行业务处理
- 2.Google官方给的MVP samples中P接收V层指令自己处理业务逻辑
- 3.P既不自己处理,也不告知M层处理,而是告知具体的业务模块,比如网络请求,数据库操作等模块去执行相关业务等
具体选用那种看团队最终框架如何定义。
基类封装
通过弱引用避免了P层对V层的持有,当Activity finish的时候能够完全腾出内存占用
- BaseModel
public abstract class BaseModel<P extends BasePresenter, CONTRACT> {
protected P p;
//业务结束,通过Presenter调用契约、合同(接口中的方法)void responseResult(T t)
public BaseModel(P p) {
this.p = p;
}
public abstract CONTRACT getContract();
}
- BaseView
public abstract class BaseView<P extends BasePresenter, CONTRACT> extends Activity {
protected P p;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//弱引用
p = getPresenter();
//绑定
p.bindView(this);
}
//让P层做什么需求
public abstract CONTRACT getContract();
//从子类中获取具体的契约
public abstract P getPresenter();
//如果Presenter层出现异常,需要告知View层
@Override
protected void onDestroy() {
super.onDestroy();
//解除绑定
p.unBindView();
}
}
- BasePresenter
public abstract class BasePresenter<V extends BaseView, M extends BaseModel, CONTRACT> {
protected M m;
private WeakReference<V> vWeakReference;
public BasePresenter() {
m = getModel();
}
public void bindView(V v) {
vWeakReference = new WeakReference<>(v);
}
public void unBindView() {
if (vWeakReference != null) {
vWeakReference.clear();
vWeakReference = null;
System.gc();
}
}
//获取View,P--V
public V getView() {
if (vWeakReference != null) {
return vWeakReference.get();
}
return null;
}
//获取子类具体契约(Model层和View层协商的共同业务)
public abstract CONTRACT getContract();
public abstract M getModel();
}
登录逻辑的实现
- LoginContract
public interface LoginContract {
interface Model {
void executeLogin(String name, String pwd) throws Exception;
}
interface View<T extends BaseEntity> {
//真实项目中们,请求结果往往是JavaBean
void handlerResult(T t);
}
interface Presenter<T extends BaseEntity> {
//登录请求(接收到View层的指令,可以自己做,也可以让Model层去执行)
void requestLogin(String name, String pwd);
//结果响应(接收到Model层处理的结果,通知View层刷新)
void responseResult(T t);
}
}
- LoginModel
public class LoginModel extends BaseModel<LoginPresenter, LoginContract.Model> {
public LoginModel(LoginPresenter loginPresenter) {
super(loginPresenter);
}
@Override
public LoginContract.Model getContract() {
return new LoginContract.Model() {
@Override
public void executeLogin(String name, String pwd) throws Exception {
//模拟网络请求
if ("zhangsan".equalsIgnoreCase(name) && "123456".equalsIgnoreCase(pwd)) {
p.getContract().responseResult(new UserInfo("腾讯", "马化腾"));
} else {
p.getContract().responseResult(null);
}
}
};
}
}
- LoginPresenter
LoginPresenter中展示了上述所说的三种类型的MVP架构方式
public class LoginPresenter extends BasePresenter<LoginActivity, LoginModel,
LoginContract.Presenter> {
@Override
public LoginContract.Presenter getContract() {
//既要履行View给他的需求,又要分配工作给Model去完成这个需求
return new LoginContract.Presenter<UserInfo>() {
@Override
public void requestLogin(String name, String pwd) {
//P层三种风格
try {
//第一种:P层不做事情,只做转发,交给M层做
m.getContract().executeLogin(name, pwd);
//第二种:让功能模块做(Library:下载,请求,图片加载等功能模块)
//HttpEngine httpEngine = new HttpEngine<>(LoginPresenter.this);
//httpEngine.post(name, pwd);
//第三种:P层自己处理(google MVP samples就是这种)
/*if ("zhangsan".equalsIgnoreCase(name) && "123456".equalsIgnoreCase(pwd)) {
responseResult(new UserInfo("腾讯", "马化腾"));
} else {
responseResult(null);
}*/
//内存泄漏测试
/*new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(60000);
}
}).start();*/
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void responseResult(UserInfo userInfo) {
//不管谁完成
getView().getContract().handlerResult(userInfo);
}
};
}
@Override
public LoginModel getModel() {
return new LoginModel(this);
}
}
最终LoginActivity实现登录逻辑的代码如下,代码简洁,易于后期维护
public class LoginActivity extends BaseView<LoginPresenter, LoginContract.View> {
private EditText nameEt;
private EditText pwdEt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
nameEt = findViewById(R.id.et_account);
pwdEt = findViewById(R.id.et_password);
}
public void doLoginAction(View view) {
String name = nameEt.getText().toString();
String pwd = pwdEt.getText().toString();
p.getContract().requestLogin(name, pwd);
}
@Override
public LoginContract.View getContract() {
return new LoginContract.View<UserInfo>() {
@Override
public void handlerResult(UserInfo userInfo) {
if (userInfo != null) {
Toast.makeText(LoginActivity.this, userInfo.toString(), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(LoginActivity.this, "登录失败!", Toast.LENGTH_SHORT).show();
}
}
};
}
@Override
public LoginPresenter getPresenter() {
return new LoginPresenter();
}
}
网友评论