记得自己刚开始的时候学习MVP模式的时候,在网上扒拉了各种各种的文章,下载各种高start的Demo,不管三七二十对葫芦画瓢一步步搭建自己的项目。开始时其实也不是特别懂,每次按照模式化的步骤写V层、M层、P层,一步步写自己项目(其实内心觉得前期的准备工作好繁琐)。可能是写的熟练了,遇到了一些问题,慢慢的也一些想法,后来就想设计一个自己使用框架。
这个系列的文章也是把自己最近学习内容的一个汇总,以此自勉,继续前行。
那下面就开始正题了,我相信大家也看过不少关于MVP模式的文章,其中关于各个层的关系及其作用内容的讲解,并且列了一大堆图解说明,这些我们直接绕过去,直接上代码我想比什么都更直接更直观:
首先定义M层:
public interface MvpModel {
}
然后是V层:
public interface MvpView {
}
在定义一个P层对View的绑定和解绑,内存上的优化:
public interface MvpPresenter<V extends MvpView> {
void attachView(V view);//View的绑定
void detachView();//View的解绑
}
接下来我要实现一个具体的P层绑定:
public class MvpBasePresenter<V extends MvpView> implements MvpPresenter<V> {
private V view;
public V getView() {
return view;
}
@Override public void attachView(V view) {
this.view = view;
}
@Override public void detachView() {
this.view = null;
}
}
MvpBasePresenter中我们先这样简单的处理后面再优化这块代码,比如view使用弱引用、动态代理对view的判空处理等。
刚刚写的这一段代码,其实就是一个中介者模式,P层就是个抽象的中介者对象,V和M就是抽象同事对象,根据具体的业务实现的M和V就是具体的同事对象,用P层隔离M和V彼此不知道对方,以达到解耦的作用。M—V—P各自的角色作用以及之间的关系就很明朗了。
我们通过一件登陆的案例来实现刚刚写的代码:
V层->抽象同事B
public interface LoginView extends MvpView {
void onLoginResult(String result);
}
M层->具体同事A
public class LoginModel implements MvpModel {
public String login(String username, String password) {
if (username.equals("wds") && password.equals("123456")) {
return "登陆成功";
} else {
return "登陆失败";
}
}
}
P->具体的中介
public class LoginPresenter extends MvpBasePresenter<LoginView> {
// 持有同事引用
// 两个同事:M层、V层
private LoginModel model;
public LoginPresenter() {
this.model = new LoginModel();
}
public void login(String username, String password) {
String loginState = this.model.login(username, password);
this.getView().onLoginResult(loginState);
}
}
在Activity中使用
public class MainActivity extends AppCompatActivity implements LoginView {
private LoginPresenter loginPresenter;
private EditText et_name;
private EditText et_password;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_name = findViewById(R.id.et_name);
et_password = findViewById(R.id.et_password);
findViewById(R.id.login).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
loginPresenter.login(et_name.getText().toString(), et_password.getText().toString());
}
});
loginPresenter = new LoginPresenter();//创建P成
loginPresenter.attachView(this);//绑定
}
@Override public void onLoginResult(String result) {
Log.e("TAG", "result :" + result);
}
@Override protected void onDestroy() {
super.onDestroy();
loginPresenter.detachView();//解绑
}
}
这样就完成了一个简单的MVP模式,在M层处理数据如http请求、数据库查询,在P层管理M和V处理业务逻辑,其实有时候会省略M层,直接在P层处理数据,但我个人还是习惯写M层。写到这里其实已经把MVP最重要的内容(,M和V各自处理自己的内容,通过P层关联M和V,以达到解耦作用),但如果我们在实际的开发中这样写代码,估计要吐血,步骤很繁琐,重复操作很多,这就不是一个合格的程序猿该做的事。
接下就对刚刚写的内容做一个简单的封装和优化,抽取一个抽象的MvpActivity,把一些共同的操作都放在这里统一处理。
在使用P层的时候,有两个重要的步骤,一个绑定(loginPresenter.attachView(this))和解绑(loginPresenter.detachView()),需要在每个使用P的Activity都要进行的操作。
如下面这代码:
public abstract class MvpActivity<V extends MvpView, P extends MvpPresenter<V>> extends AppCompatActivity implements MvpView {
private P presenter;
public P getPresenter() {
return presenter;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (presenter == null){
this.presenter = createPresenter();
}
if (presenter != null){
this.presenter.attachView((V)this);
}
}
public abstract P createPresenter();
@Override
protected void onDestroy() {
super.onDestroy();
this.presenter.detachView();
}
}
代码很简单,定义一个抽象方法createPresenter,通过向下的泛型设计,返回值为继承了MvpPresenter的Presenter,在onCreate中创建P,并做了attachView绑定,在onDestroy执行detachView解绑。
在MvpBasePresenter的attachView方法中,通过动态代理对view判空进行统一的处理,这样就不用在每次使用view前进行不等于空的处理,代码如下:
public class MvpBasePresenter<V extends MvpView> implements MvpPresenter<V> {
//弱引用
private V viewProxy;
private V view;
public V getView() {
return viewProxy;
}
@Override
public void attachView(V view) {
this.view = view;
//目标接口->实际上是MvpView
Class<?>[] interfaces = view.getClass().getInterfaces();
try {
viewProxy = (V)Proxy.newProxyInstance(view.getClass().getClassLoader(), interfaces, new ProxyInvocationHandler<V>(view));
} catch (Exception e){
e.printStackTrace();
}
}
@Override
public void detachView() {
this.view = null;
}
@Override
public void destory() {
}
private class ProxyInvocationHandler<V extends MvpView> implements InvocationHandler {
private V view;
public ProxyInvocationHandler(V view){
this.view = view;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (view != null){
//执行
return method.invoke(view, args);
}
//不存在->报错了
throw new NullPointerException("空异常");
}
}
}
最后在A具体ctivity的实现由原来的代码就变成如下::
public class MainActivity extends MvpActivity<LoginView,LoginPresenter> implements LoginView {
private EditText et_name;
private EditText et_password;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_name = findViewById(R.id.et_name);
et_password = findViewById(R.id.et_password);
findViewById(R.id.login).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
getPresenter().login(et_name.getText().toString(), et_password.getText().toString());
}
});
}
@Override public LoginPresenter createPresenter() {
return new LoginPresenter();
}
@Override public void onLoginResult(String result) {
Log.e("TAG", "result :" + result);
}
}
今天的内容就到这了😁😁
风后面是风,天空上面是天空,而你的生活可以与众不同