世上本没有路,走的人多了,便变成了路 — 鲁迅
写在前面
在上一篇文章《进阶MVP设计模式之一》中已经详细讲解了这套MVP的实现以及使用,本篇文章是基于上一篇文章的基础上进行扩展。为了能够更好的理解,建议先看上一篇文章加深印象后再来阅读,会更有收获哦。
在上一篇文章末尾说过:这套MVP设计巧妙,但是也有不如意的地方,就是不能在一个Activity/Fragment中使用多个不同的Presenter。
在实际项目中,我也遇到过此类情况,比如Activity A需要调用Presenter B中fun()函数,但是一个Activity只允许拥有一个Presenter,Activity A已经拥有Presenter A了,就不能拥有Presenter B,最终解决方案只能是将Presenter B中的fun()函数copy到Presenter A中,这样Activity A就可以调用Presenter A中的fun()函数了。如果Activity A中要大量使用其他不同Presenter中的接口呢,那么Presenter A中就要写一大坨代码,导致整个P层重复的代码太多。换一种角度思考,Activity A想要使用Presenter B,直接把Presenter B拿过来不就好了, 让一个Activity持有多个Presenter,需要谁就把谁拿过来,何乐而不为?
如何实现
划重点:接下来会以对比的方式讲解,所以一定要先看上一篇文章!!! 传送门>>>
1.RequestPresenter
不同之处是返回值类型,由Class变为Class数组,意味着可以放入多个类了。
// 注解的生命周期
@Retention(RetentionPolicy.RUNTIME)
// 注解的适用范围
@Target(ElementType.TYPE)
public @interface RequestPresenter {
Class<?>[] presenter() default {};
}
2.BaseView
这个View接口不变,一个无函数的View接口,需要结合实际需求进行扩展。
public interface BaseView {}
3.BasePresenter
这个Presenter抽象类不变,这里的View使用了弱引用,防止内存泄漏。
public abstract class BasePresenter<V extends BaseView> {
protected Context mContext;
private WeakReference<V> mView;
protected void attachView(Context context, V view) {
mContext = context;
mView = new WeakReference<>(view);
}
protected void detachView() {
if (mView != null && mView.get() != null) {
mView.clear();
}
}
protected boolean isAttachView() {
return mView != null && mView.get() != null;
}
protected V getView() {
return mView == null ? null : mView.get();
}
}
4.IPresenterStore
新增Presenter存储接口,提供了get(),put()等方法,具体是用来做什么的呢,请带着思考继续看。
public interface IPresenterStore<V extends BaseView, P extends BasePresenter<V>> {
void put(String key, P presenter);
P get(String key);
Map<String, P> getStore();
void clear();
}
5.PresenterStore
新增Presenter存储具体实现类,内部维护了一个Map,用来存储Presenter。
public class PresenterStore<V extends BaseView, P extends BasePresenter<V>> implements IPresenterStore<V, P> {
private Map<String, P> mStore;
@Override
public void put(String key, P presenter) {
if (mStore == null) {
mStore = new HashMap<>();
}
mStore.put(key, presenter);
}
@Override
public P get(String key) {
return mStore.get(key);
}
@Override
public Map<String, P> getStore() {
return mStore;
}
@Override
public void clear() {
if (mStore != null) {
mStore.clear();
}
}
}
6.IPresenterFactory
Presenter工厂接口,需要生产Presenter的工厂类来实现,依然只有一个函数。
不同之处是createPresenter()改为createPresenterStore(),返回值类型也从Presenter改为IPresenterStore,不过仍是创建Presenter的核心。
public interface IPresenterFactory<V extends BaseView, P extends BasePresenter<V>> {
IPresenterStore<V, P> createPresenterStore();
}
7.PresenterFactoryImpl
Presenter工厂的具体实现类,通过一个静态函数createFactory()返回一个该Presenter工厂实现类,并在该函数中通过注解+反射得到全部Presenter类名;当外部调用createPresenterStore()时,会先创建一个新的PresenterStore,然后通过Presenter类名newInstance()一个新的实例添加到PresenterStore中,key为Presenter类的字符串,全部Presenter创建完成后将这个PresenterStore返回,PersenterStore就创建完成了。
不同之处在于从创建一个Presenter变成了创建多个Presenter,并将多个Presenter使用PresenterStore来维护。
public class PresenterFactoryImpl<V extends BaseView, P extends BasePresenter<V>>
implements IPresenterFactory<V, P> {
private Class<P>[] mPresenters;
public static <V extends BaseView, P extends BasePresenter<V>> PresenterFactoryImpl createFactory(Class<?> clazz) {
if (!clazz.isAnnotationPresent(RequestPresenter.class)) {
throw new RuntimeException("Do not find RequestPresenter");
}
RequestPresenter requestPresenter = clazz.getAnnotation(RequestPresenter.class);
Class<P>[] pClasses = (Class<P>[]) requestPresenter.presenter();
return pClasses == null ? null : new PresenterFactoryImpl(pClasses);
}
private PresenterFactoryImpl(Class<P>[] pClasses) {
mPresenters = pClasses;
}
@Override
public IPresenterStore<V, P> createPresenterStore() {
if (mPresenters == null || mPresenters.length < 1) {
throw new RuntimeException("Presenters is null");
}
IPresenterStore<V, P> presenterStore = new PresenterStore<>();
try {
for (Class<P> pClass : mPresenters) {
presenterStore.put(pClass.toString(), pClass.newInstance());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return presenterStore;
}
8.IPresenterProxy
Presenter代理接口,其中有三个函数,可根据实际需求编写。
public interface IPresenterProxy<V extends BaseView, P extends BasePresenter<V>> {
void setFactory(IPresenterFactory<V, P> factory);
IPresenterFactory<V, P> getFactory();
P getPresenter(String key);
}
9.PresenterProxyImpl
因为Presenter工厂只有createFactory()和createPresenterStore(),而实际项目中不仅仅满足于createFactory()和createPresenterStore(),还会有其他的需要;所以使用了一个代理类来满足其他需要,所代理的是Presenter工厂和PresenterStore,可以进行扩展,比如attachView(),detachView(),release()等。
不同之处在于构造函数或设置工厂时就去创建PresenterStore,而不是在getPresenter()时去创建;由于多个Presenter是通过PresenterStore维护的,这里的getPresenter()需要传入参数key得到对应的Presenter。
public class PresenterProxyImpl<V extends BaseView, P extends BasePresenter<V>> implements IPresenterProxy<V, P> {
private IPresenterFactory<V, P> mFactory;
private IPresenterStore<V, P> mPresenterStore;
// 通过构造函数传入默认工厂
public PresenterProxyImpl(IPresenterFactory<V, P> factory) {
mFactory = factory;
mPresenterStore = mFactory.createPresenterStore();
}
// 设置工厂(默认工厂不能满足需求可以设置)
@Override
public void setFactory(IPresenterFactory<V, P> factory) {
mFactory = factory;
mPresenterStore = mFactory.createPresenterStore();
}
// 获取当前工厂
@Override
public IPresenterFactory<V, P> getFactory() {
return mFactory;
}
// 获取Presenter
@Override
public P getPresenter(String key) {
return mPresenterStore.get(key);
}
public void attachView(Context context, V view) {
for (Map.Entry<String, P> entry : mPresenterStore.getStore().entrySet()) {
P presenter = entry.getValue();
presenter.attachView(context, view);
}
}
public void detachView() {
for (Map.Entry<String, P> entry : mPresenterStore.getStore().entrySet()) {
P presenter = entry.getValue();
presenter.detachView();
}
}
public void release() {
mPresenterStore.clear();
}
10.BaseActivity
因为有了Presenter代理类,BaseActivity只需要关注Presenter代理类就可以了,无需关注Presenter工厂和PresenterStore等。
不同之处是getPresneter()需要传入key,在Activity销毁时,要调用Presenter代理类的release()函数释放PresenterStore。
public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V>> extends AppCompatActivity
implements IPresenterProxy<V, P> {
private PresenterProxyImpl<V, P> mPresenterProxy;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
getWindow().getDecorView().post(new Runnable() {
@Override
public void run() {
initPresenterProxy();
initView();
initData();
}
});
}
// 初始化Presenter代理类
private void initPresenterProxy() {
mPresenterProxy = new PresenterProxyImpl<>(PresenterFactoryImpl.<V, P>createFactory(getClass()));
mPresenterProxy.attachView(this, (V) this);
}
@Override
public void setFactory(IPresenterFactory<V, P> factory) {
mPresenterProxy.setFactory(factory);
}
@Override
public IPresenterFactory<V, P> getFactory() {
return mPresenterProxy.getFactory();
}
@Override
public P getPresenter(String key) {
return mPresenterProxy.getPresenter(key);
}
@Override
protected void onDestroy() {
super.onDestroy();
mPresenterProxy.detachView();
mPresenterProxy.release();
}
protected abstract int getLayoutId();
protected abstract void initView();
protected abstract void initData();
}
以上就是经过改良的代码,本质上就是通过一个集合来维护多个Presenter,以此达到一个Activity/Fragment持有多个Presenter的目的。
如何使用
接下来还是以一个小Demo介绍使用方式。
1.编写MVP的Model
public class LoginModel {
private static final String USERNAME = "12345";
private static final String PASSWORD = "67890";
public boolean isLoginSuccess(String username, String password) {
if (USERNAME.equals(username) && PASSWORD.equals(password)) {
return true;
}
return false;
}
}
public class RegisterModel {
public boolean isRegisterSuccess(String username, String password) {
return true;
}
}
2. 编写MVP的View
public interface ILoginView extends BaseView {
void onLoginSuccess();
void onLoginFail();
}
public interface IRegisterView extends BaseView {
void onRegisterSuccess();
void onRegisterFail();
}
3.编写MVP的Presenter
public class LoginPresenter extends BasePresenter<ILoginView> {
private LoginModel mLoginModel;
public LoginPresenter() {
mLoginModel = new LoginModel();
}
public void login(String username, String password) {
if (!isAttachView()) {
return;
}
boolean isSuccess = mLoginModel.isLoginSuccess(username, password);
if (isSuccess) {
getView().onLoginSuccess();
} else {
getView().onLoginFail();
}
}
public class RegisterPresenter extends BasePresenter<IRegisterView> {
private RegisterModel mRegisterModel;
public RegisterPresenter() {
mRegisterModel = new RegisterModel();
}
public void register(String username, String password) {
if (!isAttachView()) {
return;
}
boolean isSuccess = mRegisterModel.isRegisterSuccess(username, password);
if (isSuccess) {
getView().onRegisterSuccess();
} else {
getView().onRegisterFail();
}
}
}
4.编写xml布局文件
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/edit_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v7.widget.AppCompatEditText
android:id="@+id/edit_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@id/edit_username" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="Login"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/edit_password" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="Register"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/edit_password" />
</android.support.constraint.ConstraintLayout>
5. 编写MainActivity
@RequestPresenter(presenter = {LoginPresenter.class, RegisterPresenter.class})
public class MainActivity extends BaseActivity implements ILoginView, IRegisterView {
private AppCompatEditText mUsernameEdit;
private AppCompatEditText mPasswordEdit;
private AppCompatButton mLoginBtn;
private AppCompatButton mRegisterBtn;
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
@Override
protected void initView() {
mUsernameEdit = findViewById(R.id.edit_username);
mPasswordEdit = findViewById(R.id.edit_password);
mLoginBtn = findViewById(R.id.btn_login);
mRegisterBtn = findViewById(R.id.btn_register);
// 点击按钮时执行登录
mLoginBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String username = mUsernameEdit.getText().toString();
String password = mPasswordEdit.getText().toString();
getLoginPresenter().login(username, password);
}
});
// 点击按钮时执行注册
mRegisterBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String username = mUsernameEdit.getText().toString();
String password = mPasswordEdit.getText().toString();
getRegisterPresenter().register(username, password);
}
});
}
// 获取LoginPresenter
private LoginPresenter getLoginPresenter() {
return (LoginPresenter) getPresenter(LoginPresenter.class.toString());
}
// 获取RegisterPresenter
private RegisterPresenter getRegisterPresenter() {
return (RegisterPresenter) getPresenter(RegisterPresenter.class.toString());
}
@Override
protected void initData() {
}
@Override
public void onLoginSuccess() {
Toast.makeText(this, "登录成功!!!", Toast.LENGTH_SHORT).show();
}
@Override
public void onLoginFail() {
Toast.makeText(this, "登录失败!!!", Toast.LENGTH_SHORT).show();
}
@Override
public void onRegisterSuccess() {
Toast.makeText(this, "注册成功!!!", Toast.LENGTH_SHORT).show();
}
@Override
public void onRegisterFail() {
Toast.makeText(this, "注册失败!!!", Toast.LENGTH_SHORT).show();
}
}
运行效果如下:
![](https://img.haomeiwen.com/i15921086/bdd6473fad29bcb9.png)
![](https://img.haomeiwen.com/i15921086/9d13f20f225d42a6.png)
完结
项目地址:https://github.com/zhangjunxiang1995/Application/tree/master/mvp2
网友评论