MiQing Blog

无惧艰难,让生活更幸福更充实,努力起飞!

0%

【Android-开发框架搭建】-学会使用MVP架构的搭建项目

前言

在开发过程中MVC模式的架构是最为常见的,Android本身Activity和XML布局的结合就是比较典型的例子,使用过程中业务的逻辑、数据的处理、View的更新都会在Activity中进行这样代码的复杂度和维护成本就会增高View和Model的耦合度很高,开发者们对于这种情况都会选择进行MVC的封装拆分增加了开发的难度。

MVP是从MVC演化而来全称 Model-View-Presenter,即模型-视图-层现器。而现在Android开发架构中MVP架构已成主流,MVP模式会解除View与Model的耦合,定义了Presenter交互中间人作为View和Model之间的桥梁,它从Model中获取到数据返回给View层使View和Model之间没有耦合,并且将业务逻辑从View中抽离出来。View拥有Presenter成员变量实现逻辑接口,View将操作传递给Presenter,最后由Presenter再将结果返回View。Model就是数据仓库用于数据的存储和获取,Presenter拥有对Model进行数据的存储和获取方法。

此处贴出MVC和MVP思维导图能够清楚的看出两种模式之前的区别
示例1

使用

马上开始我们的实战MVP架构搭建

1.定义基础的IModel、IView、IPresenter接口,用于定义提供公共方法的使用

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

//添加IModel接口
public interface IModel {

/**
* 用于Model中销毁逻辑的处理
*/
void onDestroy();
}

//添加IView接口
import androidx.annotation.NonNull;
public interface IView {

/**
* 显示加载
*/
default void showLoading() {

}

/**
* 隐藏加载
*/
default void hideLoading() {

}

/**
* 显示信息
*/
void showMessage(@NonNull String message);

}


//添加IPresenter接口
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;

import org.jetbrains.annotations.NotNull;
public interface IPresenter extends LifecycleObserver {
/**
* 做一些初始化操作
*/
void onStart();

/**
* 用于Presenter中销毁逻辑的处理
*/
void onDestroy();

/**
* 继承LifecycleObserver接口用于IPresenter绑定生命周期
*/
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void onCreate(@NotNull LifecycleOwner owner);

/**
* 继承LifecycleObserver接口用于IPresenter绑定生命周期
*/
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void onDestroy(@NotNull LifecycleOwner owner);

}

2.定义抽象的Persenter业务处理类BasePresenter,关联抽象层IView和抽象IModel并实现基础的IPresenter接口。

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import android.app.Service;
import android.view.View;

import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;

import com.mi.qing.common.net.frame.util.RxLifecycleUtils;
import com.uber.autodispose.AutoDisposeConverter;

import org.jetbrains.annotations.NotNull;

import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;

public abstract class BasePresenter<M extends IModel, V extends IView> implements IPresenter {
protected CompositeDisposable mCompositeDisposable;
protected M mModel;
protected V mRootView;
private LifecycleOwner lifecycleOwner;

/**
* 注入Model和View
*
* @param model
* @param rootView
*/
public BasePresenter(M model, V rootView) {
this.mModel = model;
this.mRootView = rootView;
onStart();
}


protected <T> AutoDisposeConverter<T> bindLifecycle() {
if (null == lifecycleOwner) {
throw new NullPointerException("lifecycleOwner == null");
}
return RxLifecycleUtils.bindLifecycle(lifecycleOwner);
}


@Override
public void onStart() {

}

/**
* 处理框架销毁逻辑
*/
@Override
public void onDestroy() {
unDispose();//解除订阅
if (mModel != null) {
mModel.onDestroy();
}
this.mModel = null;
this.mRootView = null;
this.mCompositeDisposable = null;
}


/**
* 只有 {@link IPresenter} 实现了 {@link LifecycleOwner} 时,并且IPresenter被绑定到生命周期后, 此方法才会被调用
*/
@Override
public void onCreate(@NotNull LifecycleOwner owner) {
Log.e("BasePresenter", "onCreate: LifecycleOwner " );
this.lifecycleOwner = owner;

}

/**
* 只有 {@link IPresenter} 实现了 {@link LifecycleOwner} 时,并且IPresenter被绑定到生命周期后, 此方法才会被调用
*/
@Override
public void onDestroy(@NotNull LifecycleOwner owner) {
Log.e("BasePresenter", "onDestroy: LifecycleOwner " );
owner.getLifecycle().removeObserver(this);
}

/**
* 将 {@link Disposable} 添加到 {@link CompositeDisposable} 中统一管理
* 可在 View层中使用 {@link #unDispose()} 停止正在执行的 RxJava 任务,避免内存泄漏
* 目前框架已使用 {@link com.uber.autodispose.AutoDispose} 避免内存泄漏,此方法作为备用方案
*
* @param disposable
*/
public void addDispose(Disposable disposable) {
if (mCompositeDisposable == null) {
mCompositeDisposable = new CompositeDisposable();
}
mCompositeDisposable.add(disposable);//将所有 Disposable 放入容器集中处理
}

/**
* 停止集合中正在执行的 RxJava 任务
*/
public void unDispose() {
if (mCompositeDisposable != null) {
mCompositeDisposable.clear();//保证 Activity 结束时取消所有正在执行的订阅
}
}
}

3.定义抽象的BaseMvpActivity基类,通过泛型规定Presenter,并且暴露抽象方法createPresenter()给子类来创建Presenter,基类实现IView中的公共方法,减少子类代码的冗余。至于BaseMvpActivity功能根据项目业务需求进行封装。

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.mi.qing.common.net.frame.base.mvp.IPresenter;
import com.mi.qing.common.net.frame.base.mvp.IView;

public abstract class BaseMvpActivity<P extends IPresenter> extends AppCompatActivity implements IView {

protected P mPresenter;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
// 初始化Presenter
initPresenter();
}

private void initPresenter() {
mPresenter = createPresenter();
if (mPresenter != null) {
//mPresenter绑定Activity生命周期用于内部处理Rxjava流销毁
getLifecycle().addObserver(mPresenter);
mPresenter.onStart();
}
}

@Override
protected void onDestroy() {
super.onDestroy();
// 执行Presenter销毁逻辑
if (mPresenter != null) {
mPresenter.onDestroy();
mPresenter = null;
}
}

@Override
public void showLoading() {
// 这里实现自己的加载弹框
}

@Override
public void hideLoading() {
// 取消弹框
}

@Override
public void showMessage(String message) {
// 消息提示
}

/**
* 创建Presenter
*
* @return Presenter
*/
protected abstract P createPresenter();

/**
* 获取当前activity的id
*
* @return 当前xml的布局res ID
*/
protected abstract int getLayoutId();

}

4. 使用MVP架构,添加契约接口Contract,通过契约接口来管理Model、View、Presenter的所有接口,维护起来也方便,同时Model、View、Presenter关联一一对应一目了然,

并有效地减少类的数目。

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

import com.mi.qing.common.net.frame.base.mvp.IModel;
import com.mi.qing.common.net.frame.base.mvp.IView;
import com.mi.qing.common.net.frame.bean.BaseApiResult;

import io.reactivex.Observable;

public interface TestContract {

interface View extends IView {
/**
* 登录成功
*/
void onLoginSuccess(String message);

}

interface Presenter {
/**
* 发起登录
*/
void login();
}


/**
* 模拟请求登录,此处用的前面文章里测试的接口
*/
interface Model extends IModel {
Observable<BaseApiResult<String>> getTop();
}

}

5. 创建测试TestPresenter类处理登录的逻辑,继承BasePresenter关联契约接口中定义的Model和View接口并实现定义的Presenter接口

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

public class TestPresenter extends BasePresenter<TestContract.Model,TestContract.View> implements TestContract.Presenter{

/**
* 注入Model和View
*
* @param model
* @param rootView
*/
public TestPresenter(TestContract.Model model, TestContract.View rootView) {
super(model, rootView);
}

@Override
public void login() {
mRootView.showLoading();
mModel.getTop()
//使用AutoDispose处理请求销毁,防止内存泄漏
.as(bindLifecycle())
.subscribe(data->{
mRootView.onLoginSuccess("登录成功啦");
mRootView.hideLoading();
},throwable -> {
throwable.printStackTrace();
});
}
}

6. 创建测试TestModel类处理登录的数据获取,实现契约接口定义的Model接口,用于TestPresenter类调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

import com.mi.qing.common.net.frame.bean.BaseApiResult;
import com.mi.qing.common.net.source.impl.TestServiceImpl;

import io.reactivex.Observable;

public class TestModel implements TestContract.Model{


@Override
public void onDestroy() {

}

@Override
public Observable<BaseApiResult<String>> getTop() {
return TestServiceImpl.getInstance().getTop();
}
}

7. 添加测试的View类MvpTestActivity,继承BaseMvpActivity泛型定义TestPresenter类,并实现契约接口中定义的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
29
30
31
32
33
34
35
36
37
38
39

import android.annotation.SuppressLint;
import android.view.View;
import android.widget.Toast;

import com.mi.qing.common.net.frame.base.BaseMvpActivity;
import com.mi.qing.common.net.mvp.TestContract;
import com.mi.qing.common.net.mvp.TestModel;
import com.mi.qing.common.net.mvp.TestPresenter;

public class MvpTestActivity extends BaseMvpActivity<TestPresenter> implements TestContract.View {



//此方法创建Presenter类,注入Model和View
@Override
protected TestPresenter createPresenter() {
TestModel testModel = new TestModel();
return new TestPresenter(testModel, this);
}

@Override
protected int getLayoutId() {
return R.layout.activity_mvp_test;
}

//View中定义的接口方法,Presenter类中会回调信息给此接口,用于View层处理数据
@SuppressLint("ShowToast")
@Override
public void onLoginSuccess(String message) {
Toast.makeText(MvpTestActivity.this, message, Toast.LENGTH_SHORT).show();
}


//此处View联系Presenter发起登录请求,Presenter收到后调用Model进行数据处理
public void clickLogin(View view) {
mPresenter.login();
}
}

使用效果截图
示例2

总结

基础的MVP架构搭建完毕,读者可按需调整内部逻辑及处理。没有恒古不变的架构,只有在变化中找出适合自己项目的架构。后续章节还会介绍MVVM架构的有点及搭建方式,技术在于实践马上开始搭建属于自己的MVP架构吧。

框架及Demo源码
源码地址 MiQingWang/CommonNetFrame

-------- 本文章已被掏空 学无止境下一章 --------