在公司项目中使用RxJava和MVP已经很久了,从一开始使用到不断完善这个结构,最近也看到很多QQ好友有类似这方面的问题,就想着把这个抽出来放到github上面,供大家参考。
先说说这个mvp把, mvp我自己的理解就是通过一个中间类,做一个View和Model之间的一个联系类,view和Model不再直接联系,达到程序解耦的目的。
MVP是一种设计模式,是一种思想,没有一个标准的实现过程,但是也要遵循一定的规则。MVP是基于接口的,我们都知道在程序中使用接口,在很多场景就是为了达到程序解耦。
接下来看一下MVP的一个模型图,来帮助我们更好地理解MVP模式。
使用MVP我自己感觉到最大的好处就是,程序变得简洁了很多,减轻了Activity的压力,把业务逻辑都放到presenter里面去做,也容易维护,但其实在MVP这种模式中,如果使用的不恰当的话,是非常容易导致内存泄漏的,因为presenter通常都需要持有Activity、Fragment的引用,来达到控制view的目的。
接下来我说说自己是如何设计这个MVP的结构的,当然也是参考了很多大神的源码,最后通过自己不断总结出来的一套适合自己的结构。
首先我们建立一个IBase类。这个是为我们的View层提供的一个接口,需要使用到Presenter的Activity都需要去实现这个IBase。里面就是声明几个基本的方法。
public interface IBase {
//拿到ApplicationContext
Context getMApplicationContext();
//拿到当前类的Context
Context getMContext();
//判断有无网络
boolean hasNet();
//显示一个吐司框
void showToast(String s);
...
}
这里我只列了几个基本的方法,首先 ApplicationContext我们在访问数据库,访问Sp等场景都会需要用到。Context就不用说了,判断有无网络,可以在发出网络请求的时候,先判断有无网络。
有了IBase我们可以开始写自己的BasePresenter
public abstract class BasePresenter<T> {
String TAG = "BasePresenter";
//view接口类型的弱引用
protected Reference<T> mViewRef;
private CompositeSubscription mCompositeSubscription;
public void attachView(T view) {
mViewRef = new WeakReference<T>(view);
}
protected T getView() {
return mViewRef.get();
}
public boolean isViewAttached() {
return mViewRef != null && mViewRef.get() != null;
}
public void dettachView() {
if (mViewRef != null) {
mViewRef.clear();
mViewRef = null;
}
}
//添加一个Subscription
protected void addSubscription(Subscription s) {
if (this.mCompositeSubscription == null) {
this.mCompositeSubscription = new CompositeSubscription();
}
this.mCompositeSubscription.add(s);
}
//解除订阅
public void unsubcrible() {
if (this.mCompositeSubscription != null) {
this.mCompositeSubscription.unsubscribe();
}
}
}
简单说一下思路,在attachView的时候把View注册到Presenter中(生成一个弱引用,主要是防止内存泄漏),然后通过getView拿到view的一个弱引用,声明方式均为接口。dettachView的时候释放弱引用,如果忘记释放了,或者在Activity finish的时候还不能结束网络请求,可以不调用dettachView,在网络请求结束后会自动释放。
addSubscription用于添加一个Subscription对象,unsubcrible解除所有订阅,在Activity finish的时候取消请求,可以先把请求的Subscription添加进来, finish的时候取消订阅。
接下来在我们的BaseActivity和BaseFragment中去实现这个IBase。
public abstract class BaseActivity<V,T extends BasePresenter<V>> extends AppCompatActivity implements IBase {
protected T mPresenter;
protected abstract T createPresenter();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = createPresenter();
}
//实现IBase中的接口
...
}
public abstract class BaseFragment<V, T extends BasePresenter<V>> extends Fragment implements IBase {
protected T mPresenter;
protected abstract T createPresenter();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = createPresenter();
//实现IBase中的接口
...
}
基本框架搭建完成。
新建一个Activity或者Fragment、
比如,新建一个TestActivity,首先,我们要建一个ITest接口。
public interface ITest extends IBase {
void showData(String data);
}
然后建一个TestPresenter, 严格来说是应该建一个ITestPresenter的,但是我把这个省了。
public class TestPresenter extends BasePresenter<ITest> {
private ITest iview;
public TestPresenter(ITest main) {
this.attachView(main);
iview = getView();
}
public void getData() {
iview.showData("hello , i'm mvp");
}
}
最后我们建一个TestActivity。
public class TestActivity extends BaseActivity<ITest, TestPresenter> implements ITest {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
}
@Override
protected TestPresenter createPresenter() {
return new TestPresenter(this);
}
@Override
public void showData(String data) {
showToast(data);
}
}
到这里一个MVP的框架搭建和使用基本完成了。看了这么多是不是感觉程序变得复杂了好多,不过一旦你真正理解了,并且应用到程序中,你会发现这种模式给你带来的巨大的好处。
以上代码均已上传到github,欢迎star。
https://github.com/sunflowerseat/MVPDemo
不过MVP每次要建这么多的类,的确是让人有点蛋疼,尤其是加上Dagger2 然后再加Presenter的接口的时候,随便一个activity就得新建五六个类。。。就算是复制粘贴也能把人累个半死。
作为程序员我们总能想到让自己偷懒的办法的, 真的每次建五六个类, 时间久了也是会疯的。
所幸的是最近不论是android还是web我们都能够是用模板工具,为我们生成许多重复的代码。
在android中我们可以使用FreeMarker语法按照自己的代码习惯编写一个MVPActivity和MVPFragment。
我也把模板Acitivity的代码发到了github上,供大家参考学习,共同进步。
https://github.com/sunflowerseat/MVPDemo/tree/master/MVPActivityTemplate/MVPActivity
https://github.com/sunflowerseat/MVPDemo/tree/master/MVPActivityTemplate/MVPActivity
下一篇博客会讲讲如何自定义一个Activity模板。
对本文内容有任何疑问欢迎加群讨论:283272067