如题,MVP架构目前是最火的安卓架构了。为什么他如此受推崇呢?今天我们就来揭开它神秘的面纱。首先我们来个简易版的mvp(人懒,直接上代码了)
实现思路如下:
1、首先我们先定义一个接口,用来规定针对这个界面逻辑View需要作出的动作的接口。
2、让Activity实现这个接口中的方法,也就是V层
3、创建一个类,用来封装之前的网络请求过程,也就是M层
4、再创建一个类,用来处理M层和V层之间的通信,也就是P层
1.首先定义V层接口LoginView
/**
* Author:liuzj
* Time:2018/3/7
* Description: V层接口
*/
public interface LoginView {
/**
* 展示加载过程
*/
void showLoading();
void onSuccess(String response);
void onFaile(String error);
}
activity或者fragment去实现它
/**
* 1.简单型mvp模式
*/
public class Demo1Activity extends AppCompatActivity implements LoginView{
private TextView content;
private ProgressBar loadview;
private LoginPresenter loginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
content = (TextView) findViewById(R.id.content);
loadview = (ProgressBar) findViewById(R.id.pb);
//引入P层
loginPresenter = new LoginPresenter(this);
loginPresenter.doLogin();
}
@Override
public void showLoading() {
loadview.setVisibility(View.VISIBLE);
}
@Override
public void onSuccess(String response) {
loadview.setVisibility(View.GONE);
content.setText(response);
}
@Override
public void onFaile(String error) {
loadview.setVisibility(View.GONE);
}
}
2.定义M层LoginModel(数据相关)
/**
* Author:liuzj
* Time:2018/3/7
* Description:M层
*/
public class LoginModel {
public void Login(CallBack<String> callBack) {
callBack.onResponse("你好!Mvp架构师");
}
}
给出CallBack代码:
/**
* Author:liuzj
* Time:2018/3/7
* Description: 数据回调接口
*/
public interface CallBack<T> {
void onResponse(T response);
void onFailure(String error);
}
3.重中之重定义P层LoginPresenter
/**
* Author:liuzj
* Time:2018/3/7
* Description:
*/
public class LoginPresenter {
/*P层要持有M层和V层的引用*/
private LoginModel model;
private LoginView view;
//怎么传view进来? ——>构造方法
public LoginPresenter(LoginView view) {
this.model = new LoginModel();
this.view = view;
}
public void doLogin() {
/*
* 在P层刷新UI
* */
view.showLoading();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
model.Login(new CallBack<String>() {
@Override
public void onResponse(String response) {
view.onSuccess(response);
}
@Override
public void onFailure(String error) {
view.onFaile(error);
}
});
}
},1500);
}
}
到这里一个简易的MVP就写好了。但是存在一个问题,假设我们在进行网络请求的过程中Activity或者说V层销毁了,而P层还持有V层的引用,这样会造成内存泄露。怎么解决?
——>我们可以在presenter里面设计一个绑定和解绑操作
改写后的presenter如下:
public class LoginPresenter2 {
/*P层要持有M层和V层的引用*/
private LoginModel model;
private LoginView view;
//怎么传view进来? ——>构造方法
public LoginPresenter2(LoginView view) {
this.model = new LoginModel();
this.view = view;
}
public void doLogin() {
/*
* 在P层刷新UI
* */
view.showLoading();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
model.Login(new CallBack<String>() {
@Override
public void onResponse(String response) {
view.onSuccess(response);
}
@Override
public void onFailure(String error) {
view.onFaile(error);
}
});
}
},1500);
}
/**
* 绑定V层
* @param view
*/
public void attach(LoginView view) {
this.view = view;
}
/**
* 解绑
*/
public void detach() {
this.view = null;
}
}
我这里没有写请求网络如果有请求网络操作,我们还得做取消操作。跟着detach后面做取消就可以了,这里就不给出了。
改写后的Activity代码如下:
public class Demo2Activity extends AppCompatActivity implements LoginView{
private TextView content;
private ProgressBar loadview;
private LoginPresenter2 loginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
content = (TextView) findViewById(R.id.content);
loadview = (ProgressBar) findViewById(R.id.pb);
//引入P层
loginPresenter = new LoginPresenter2();
loginPresenter.attach(this);
loginPresenter.doLogin();
}
@Override
public void showLoading() {
loadview.setVisibility(View.VISIBLE);
}
@Override
public void onSuccess(String response) {
loadview.setVisibility(View.GONE);
content.setText(response);
}
@Override
public void onFaile(String error) {
loadview.setVisibility(View.GONE);
}
@Override
protected void onDestroy() {
super.onDestroy();
loginPresenter.detach();
/*有网络请求操作在这里要做取消操作*/
}
}
内存泄露的问题解决了,但是开发过程中我们是会有有很多的P层和V层的,每次都要写绑定,解绑,V层再调用绑定,解绑。是不是显得代码冗余。怎么解决代码冗余? ——>抽取基类——>用Presenter基类,Activity(或者其他的view)基类来做这些事情。而且view还不能写死,我们这里采用泛型设计。
思路:
1.创建一个基类View,让所有View接口都必须实现,这个View可以什么都不做只是用来约束类型的
2.创建一个基类的Presenter,在类上规定View泛型,然后定义绑定和解绑的抽象方法,让子类去实现,对外在提供一个获取View的方法,
让子类直接通过方法来获取View
3.创建一个基类的Activity,声明一个创建Presenter的抽象方法,因为要帮子类去绑定和解绑那么就需要拿到子类的Presenter才行,但是又不能随便一个类都能绑定的,因为只有基类的Presenter中才定义了绑定和解绑的方法,所以同样的在类上可以声明泛型在,方法上使用泛型来达到目的。
4.修改Presenter和Activity中的代码,各自继承自己的基类并去除重复代码
1.创建View层顶级接口,让所有的view都去实现它
//V层的顶层接口,可不做任何事情,只是用来约束类型
public interface IMvpView {
}
2.创建一个基类的Presenter,在类上规定View泛型,然后定义绑定和解绑的方法,对外在提供一个获取View的方法,让子类直接通过方法来获取View使用即可
public abstract class AbsMvpPresenter<V extends IMvpView> {
private V view;
/**
* 绑定V层
* @param view
*/
public void attach(V view) {
this.view = view;
}
/**
* 与V层解绑
*/
public void detach() {
this.view = null;
}
/**
* 提供一个获取view的方法,后面的子类可通过此方法获取V层
* @return
*/
public V getView() {
return this.view;
}
}
3.创建基类Activity(或者其他的view)因为要用presenter去调用绑定和解绑,所以我们可以提供一个抽象方法交给子类去创建presenter。但是presenter又不能写死,这里采用泛型继承自AbsMvpPresenter
//规定子类具体的View需要继承自IMvpView,子类具体的presenter需要继承自AbsMvpPresenter
public abstract class AbsMvpActivity<V extends IMvpView, P extends AbsMvpPresenter<V>> extends AppCompatActivity implements IMvpView {
private P presenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (presenter == null) {
presenter = createPresenter();
}
if (presenter == null) {
throw new NullPointerException("presenter not be null!");
}
presenter.attach((V)this);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (presenter != null) {
presenter.detach();
}
}
/**
* 对子类提供获取presenter的方法
* @return
*/
public P getPresenter() {
return presenter;
}
/**
* 创建presenter,让子类自己去实现,获取自己的presenter
* @return
*/
protected abstract P createPresenter();
}
4.让presenter继承AbsMvpPresenter,activity继承AbsMvpActivity,编写代码
LoginPresenter3
public class LoginPresenter3 extends AbsMvpPresenter<LoginView3>{
private LoginModel model;
public LoginPresenter3() {
this.model = new LoginModel();
}
public void doLogin() {
/*
* 在P层刷新UI
* */
getView().showLoading();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
model.Login(new CallBack<String>() {
@Override
public void onResponse(String response) {
getView().onSuccess(response);
}
@Override
public void onFailure(String error) {
getView().onFaile(error);
}
});
}
}, 1500);
}
}
Demo3Activity
public class Demo3Activity extends AbsMvpActivity<LoginView3, LoginPresenter3> implements LoginView3 {
private TextView content;
private ProgressBar loadview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
content = (TextView) findViewById(R.id.content);
loadview = (ProgressBar) findViewById(R.id.pb);
//引入P层
getPresenter().doLogin();
}
@Override
public void showLoading() {
loadview.setVisibility(View.VISIBLE);
}
@Override
public void onSuccess(String response) {
loadview.setVisibility(View.GONE);
content.setText(response);
}
@Override
public void onFaile(String error) {
loadview.setVisibility(View.GONE);
}
@Override
protected LoginPresenter3 createPresenter() {
return new LoginPresenter3();
}
}
貌似看起来已经很完美了,还能再优化吗?
我们来分析一下:
1.每个子类都要重写父类创建Presenter的方法,创建一个Presenter并返回,这一步我们也可以让父类帮忙干了,怎么做呢?
我们可以采用注解的方式,在子类上声明一个注解并注明要创建的类型,剩下的事情就让父类去做了,但是父类得考虑如果子类不想这么干怎么办,那也还是不能写死吧,可以使用策略模式加工厂模式来实现,我们默认使用这种注解的工厂 ,但是如果子类不喜欢可以通过父类提供的一个方法来创建自己的工厂。
2.Presenter真正的创建过程,我们可以将它放到真正使用Presenter的时候再创建,这样的话可以稍微优化一下性能问题
3.界面有可能会意外销毁并重建,Activity、Fragment、View都可以在销毁的时候通过onDestroy释放一些资源并在onSaveInstanceState方法中存储一些数据然后在重建的时候恢复,但是有可能Presenter中也需要释放一些资源存储一些数据,那么上面的结构就不能满足了,我们可以给Presenter增加生命周期的方法,让Presenter和V层生命周期同步就可以做到了
4.第三步中我们又给Presenter加入了一些生命周期的方法,再加上Presenter的创建绑定和解绑的方法,那么如果我们在创建一个MvpFragment基类,或者View的基类那么这么多的代码岂不是都要copy一份吗,而且看起来也很不清晰,这里我们可以采用代理模式来优化一下。
1.采用工厂模式才创建Presenter,首先创建一个工厂接口
//presenter工厂接口 指定View和Presenter只能继承自IBaseMvpView和BaseMvpPresenter
public interface IPresenterFactory<V extends IBaseMvpView, P extends BaseMvpPresenter<V>> {
/**
* 创建presenter的方法
* @return
*/
P createPresenter();
}
2..然后创建一个注解,因为我们默认使用注解来创建工厂
//创建presenter的注解
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface CreatePresenter {
Class<? extends BaseMvpPresenter> value();
}
注解工厂:
//工厂实现类
public class PresenterFactoryImpl<V extends IBaseMvpView, P extends BaseMvpPresenter<V>> implements IPresenterFactory<V, P> {
private Class<P> presenterClazz;
//根据注解创建presenter的工厂实现类
public static <V extends IBaseMvpView, P extends BaseMvpPresenter<V>> PresenterFactoryImpl<V, P> createFactory(Class<?> viewClazz) {
CreatePresenter annotation = viewClazz.getAnnotation(CreatePresenter.class);
Class<P> aClass = null;
if (annotation != null) {
aClass = (Class<P>) annotation.value();
}
return aClass == null ? null : new PresenterFactoryImpl<V, P>(aClass);
}
public PresenterFactoryImpl(Class<P> presenterClazz) {
this.presenterClazz = presenterClazz;
}
@Override
public P createPresenter() {
try {
return this.presenterClazz.newInstance();
} catch (Exception e) {
throw new RuntimeException("Presenter 创建失败!检查是否声明了@CreatePresenter(xxPresenter.class)注解");
}
}
}
3.我们说了不能写死这个工厂,那么我们需要使用者可以自定义,那么我们还需要给使用者提供一个设置的方法,我们定义一个接口提供设置工厂、获取工厂、获取Presenter的方法,然后让V层来实现这个接口,这样V层的子类就可以通过相应的方法使用了
//提供代理接口给V层使用 交给V层实现
public interface IPresenterProxy<V extends IBaseMvpView, P extends BaseMvpPresenter<V>> {
/**
* 设置presenter创建工厂
* @param factory
*/
void setPresenterFactory(IPresenterFactory<V, P> factory);
IPresenterFactory<V, P> getPresenterFactory();
/**
* 获取创建的presenter
* @return
*/
P getPresenter();
}
4.给Presenter增加生命周期的方法
//指定绑定的view都要继承自IBaseMvpView
public class BaseMvpPresenter<V extends IBaseMvpView> {
//presenter也需要根据view的生命来释放资源,保存数据等,所以这里增加生命周期方法
private V view;
/**
* 创建presenter时调用
* @param savedState
*/
public void onCreatePresenter(Bundle savedState) {
}
/**
* 绑定V层
* @param view
*/
public void onAttachView(V view) {
this.view = view;
}
/**
* 与V层解绑
*/
public void onDetachView() {
this.view = null;
}
/**
* presenter被销毁时调用
*/
public void onDestoryPresenter() {
}
/**
* 在Presenter意外销毁的时候被调用,它的调用时机和Activity、Fragment、View中的onSaveInstanceState时机相同
*
* @param outState
*/
public void onSaveInstanceState(Bundle outState) {
}
/**
* 提供一个获取view的方法,后面的子类可通过此方法获取V层
* @return
*/
public V getView() {
return this.view;
}
}
5.创建一个代理来管理Presenter的生命周期方法
//presenter代理的实现类 用来管理生命周期和view之间的关联
public class BaseMvpPresenterProxyImpl<V extends IBaseMvpView, P extends BaseMvpPresenter<V>> implements IPresenterProxy<V, P> {
/**
* 获取onSaveInstanceState中bundle的key
*/
private static final String PRESENTER_KEY = "presenter_key";
/**
* Presenter工厂类
*/
private IPresenterFactory<V, P> mFactory;
private P mPresenter;
private Bundle mBundle;
private boolean mIsAttchView;
public BaseMvpPresenterProxyImpl(IPresenterFactory<V, P> mFactory) {
this.mFactory = mFactory;
}
@Override
public void setPresenterFactory(IPresenterFactory<V, P> factory) {
if (mPresenter != null) {
throw new IllegalArgumentException("这个方法只能在getPresenter()之前调用,如果Presenter已经创建则不能再修改");
}
this.mFactory = factory;
}
@Override
public IPresenterFactory<V, P> getPresenterFactory() {
return this.mFactory;
}
@Override
public P getPresenter() {
if (mFactory != null) {
if (mPresenter == null) {
mPresenter = mFactory.createPresenter();
mPresenter.onCreatePresenter(mBundle == null ? null : mBundle.getBundle(PRESENTER_KEY));
}
}
return mPresenter;
}
/**
* 绑定Presenter和view
*
* @param mvpView
*/
public void onAttachView(V mvpView) {
if (getPresenter() != null && !mIsAttchView) {
getPresenter().onAttachView(mvpView);
mIsAttchView = true;
}
}
/**
* 销毁Presenter持有的View
*/
private void onDetachView() {
if (getPresenter() != null && mIsAttchView) {
getPresenter().onDetachView();
mIsAttchView = false;
}
}
/**
* 销毁Presenter
*/
public void onDestroy() {
if (getPresenter() != null) {
onDetachView();
getPresenter().onDestoryPresenter();
mPresenter = null;
}
}
/**
* 意外销毁的时候调用
*
* @return Bundle,存入回调给Presenter的Bundle和当前Presenter的id
*/
public Bundle onSaveInstanceState() {
Bundle bundle = new Bundle();
if (getPresenter() != null) {
Bundle presenterBundle = new Bundle();
//回调Presenter
getPresenter().onSaveInstanceState(presenterBundle);
bundle.putBundle(PRESENTER_KEY, presenterBundle);
}
return bundle;
}
/**
* 意外关闭恢复Presenter
*
* @param savedInstanceState 意外关闭时存储的Bundler
*/
public void onRestoreInstanceState(Bundle savedInstanceState) {
mBundle = savedInstanceState;
}
}
6.最后V层实现,首先实现设置工厂的接口,然后创建一个代理并传入默认工厂,在V层生命周期中使用代理去实现管理Presenter的生命周期(Activity继承这个Base类就可以了)
//使用代理模式来代理Presenter的创建、销毁、绑定、解绑以及Presenter的状态保存,其实就是管理Presenter的生命周期
public abstract class BaseMvpActivity<V extends IBaseMvpView, P extends BaseMvpPresenter<V>>
extends AppCompatActivity implements IPresenterProxy<V, P> {
// 根据V层的生命周期用presenter代理来管理presenter的生命周期
private static final String KEY_SAVE_PRESENTER = "key_save_presenter";
/**
* 创建被代理对象,传入默认Presenter的工厂
*/
private BaseMvpPresenterProxyImpl<V, P> presenterProxy = new BaseMvpPresenterProxyImpl<>(PresenterFactoryImpl.<V, P>createFactory(getClass()));
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
//重新创建时获取之前保存的Bundle
presenterProxy.onRestoreInstanceState(savedInstanceState.getBundle(KEY_SAVE_PRESENTER));
}
presenterProxy.onAttachView((V) this);
}
@Override
protected void onDestroy() {
super.onDestroy();
presenterProxy.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//存入这个Bundle
outState.putBundle(KEY_SAVE_PRESENTER, presenterProxy.onSaveInstanceState());
}
@Override
public void setPresenterFactory(IPresenterFactory<V, P> factory) {
presenterProxy.setPresenterFactory(factory);
}
@Override
public IPresenterFactory<V, P> getPresenterFactory() {
return presenterProxy.getPresenterFactory();
}
@Override
public P getPresenter() {
return presenterProxy.getPresenter();
}
}
最后看一下怎么使用?
@CreatePresenter(LoginPresenter.class)
public class MvpActivity extends BaseMvpActivity<LoginView, LoginPresenter> implements LoginView {
private TextView content;
private ProgressBar pb;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp);
content = (TextView) findViewById(R.id.content);
pb = (ProgressBar) findViewById(R.id.pb);
getPresenter().doLogin();
}
@Override
public void showLoading() {
pb.setVisibility(View.VISIBLE);
}
@Override
public void onSuccess(String response) {
pb.setVisibility(View.GONE);
content.setText(response);
}
@Override
public void onFaile(String error) {
pb.setVisibility(View.GONE);
Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
}
}
集成Lce的流程,我就不讲了,我的Demo里面有并且已经封装成了一个lib库,你用的时候直接引进即可。
代码传送门: https://github.com/liu20160703/mvpLib