MVP介绍

MVP设计模式分成了View、Presenter、Model层,不同于原来的MVC,view中不在存放业务逻辑-只是展示页面,而由Presenter来统筹全局-处理逻辑
介绍几个官方MVP的写法
官方Demo
优秀实践
MVP与Lifecycle结合

MVP分析

官方MVP建议使用Activity里面创建Presenter,View使用Fragment,一图胜千言
链接图片

实际中,我们的view可以是Activity或者Fragment,完全不需要一个Activity来嵌套一层view

####MVP模式封装

View

首先View接口,我们没有特定的方法需要实现,但是为了配合Presenter,我们的IView是个空接口。后面view只是简单的实现即可

1
2
public interface IMvpView{
}

Presenter

Presenter中需要与View绑定,同时还需要知道view的生命周期-至少知道attach和detach

1
2
3
4
5
6
7
8
9
10
11
12
public interface IMvpPresenter<V extends IMvpView> {

/**
* 初始化Presenter时,用于presenter与view绑定
*/
void onBind(V view);

void onViewAttach();

void onViewDetach();

}

Presenter的基类

Presenter中公共的,我们会做与view的绑定和解绑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public abstract class MvpPresenter<V extends IMvpView> implements IMvpPresenter<V> {

protected V mView;

protected Context mContext;

@Override
public void onBind(V view) {
mView = view;
if (view instanceof Fragment) {
mContext = ((Fragment) view).getContext();
} else if (view instanceof Activity) {
mContext = (Activity) view;
} else if (view instanceof View) {
mContext = ((View) view).getContext();
}
}

@Override
public void onViewAttach() {

}

@Override
public void onViewDetach() {
mView = null;
}
}
  • 在detach时吧mView置空,会导致调用mView出现空指针问题

这里我想过使用生成代码的方式判断mView的值,但是一直无法完美的实现。最后使用了空对象设计模式来实现

1
2
3
4
5
6
7
8
9
10
private V mView;

protected V getView() {
if (mView == null) {
return createDummyView();
}
return mView;
}

protected abstract V createDummyView();

Helper类

View与Presenter的绑定,可以简单的在创建presenter的时候手动调用,如

1
2
#View(Fragment|Activity)
new XPresenter().onBind(this);

但是不乏我们忘记,所以可以写一个帮助类来完成

1
2
3
4
5
6
7
8
9
10
public class MvpLifecycleHelper {

/**
* 把View和Presenter关联起来
*/
public static <V extends IMvpView, P extends IMvpPresenter<? super V>> P from(V view, P presenter) {
presenter.onBind(view);
return presenter;
}
}

这里写泛型的时候出现了一些小问题,可以查看另一篇博客
这样我们绑定的时候使用如下

1
MvpLifecycleHelper.from(this,new LoginPresenter());

到此我们的MVP的简单封装已经完成。
但是现在presenter的周期还是需要view手动去调用的,这样还是很不友好

结合Lifecycle

其实我们要做的也很简单,只需要在onBind中添加presenter给lifecycle,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public abstract class PresenterLifecycle<V extends IMvpView> extends MvpPresenter<V> implements LifecycleObserver, IPresenterLifecycle<V> {


@Override
public void onBind(V view) {
super.onBind(view);
if (view instanceof LifecycleOwner) {
Lifecycle lifecycle = ((LifecycleOwner) view).getLifecycle();
//会立马调用对应的监听
lifecycle.addObserver(this);
if (lifecycle.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
this.onViewAttach();
}
}
}

@Override
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onViewAttach() {
mLifecycleSubject.onNext(Lifecycle.Event.ON_CREATE);
}


@Override
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
mLifecycleSubject.onNext(Lifecycle.Event.ON_START);
}

@Override
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
mLifecycleSubject.onNext(Lifecycle.Event.ON_RESUME);
}

@Override
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
mLifecycleSubject.onNext(Lifecycle.Event.ON_STOP);
}

@Override
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onViewDetach() {
mLifecycleSubject.onNext(Lifecycle.Event.ON_DESTROY);
super.onViewDetach();
}
}

由于addObserver时,会调用一次对应的周期,所以我们可以完全不用手动调用onViewAttach()。
唯一存在的可能是我们在onResume才绑定presenter(这种可能很低),所以添加了一下周期判断

至此整个封装完成,源码已经同步到github,可下载使用