Android MVP 模式

MVP

MVP(Model-View-Presenter)是 MVC 的演化版本,会将业务逻辑和视图逻辑抽象到接口中。MVP 的角色定义如下:

  • Model:负责数据的管理。主要提供数据的存取能力。Presenter 需要通过 Model 层来存储、获取数据。
  • View:负责UI的显示。处理用户事件和视图部分的展示。在 Android 中,它可能是 Activity、Fragment 类或者是某个 View 控件。
  • Persenter:负责逻辑控制。作为 View 和 Model 之间沟通的桥梁。

View层产生事件,通知Persenter层,Persenter层则通知Model层更新数据,

Model层更新数据后,返回并通知Persenter层,Persenter层再通知View层更新界面。

优点;完全解耦View层和Model层。Model,View,Presenter各司其职,职责更清晰。甚至可由多人分工合作完成。(当然,灵活修改,适合自己的项目才最好,比如有时Model层的业务逻辑也可以放在Presenter层,从而取消Model层)

缺点;时间上来讲导致开发效率低下,因为需要借助接口回调的方式转发消息,从而导致接口类文件增多(Model,View,Presenter都需要各自的接口,再加上他们各自的实现,也就是说每一个页面都会有6个java文件,而每一个类的加载又会消耗资源),且实现类无法避免许多无用的空实现。(当然,可通过泛型参数、抽象父类的方式,将一些公用的Model及Presenter抽象出来)当然还有一个问题,MVP 个人实现差异比较大。

示例

同时,结合 RxJava 和 Retrofit 来做网络请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Contract {
/**
* M层
*/
public interface ContractModel{
void getDataList(String id,String type ,BaseCallbackListener<UserBean> callbackListener);
}
/**
* V层
*/
public interface ContractView{
void showView(UserBean user);
}
/**
* P层
*/
public interface ContractPresenter extends BasePresenter {
void startRequestData(String id,String type);
}
}
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
public class ModelIml implements Contract.ContractModel{

@Override
public void getDataList(String id,String type, final BaseCallbackListener<UserBean> callBack) {
RetrofitUtils.newInstence()//实例化Retrofit对象
.create(Info.class)//创建Rxjava---->LoginService对象
.getDataList(id)
.subscribeOn(Schedulers.newThread())//在新线程中执行登录请求
.observeOn(AndroidSchedulers.mainThread())//在主线程中执行
.subscribe(new Observer<UserBean>() {
@Override
public void onSubscribe(Disposable d) {
callBack.onStart();
}

@Override
public void onNext(UserBean user) {
if ("200".equals(user.getCode())) {
callBack.onNext(user);
}else {
callBack.onError(user.getMsg());
}
}

@Override
public void onError(Throwable e) {
Log.e("TAG",e.getMessage());
e.printStackTrace();
if (e instanceof HttpException) {
HttpException httpException = (HttpException) e;
//httpException.response().errorBody().string()
int code = httpException.code();
if (code == 500 || code == 404) {
callBack.onError("服务器出错");
}
}else if (e instanceof ConnectException) {
callBack.onError("网络断开,请打开网络!");
} else if (e instanceof SocketTimeoutException) {
callBack.onError("网络连接超时!!");
} else {
callBack.onError("发生未知错误" + e.getMessage());
}
}

@Override
public void onComplete() {

}
});

}
}
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
public class MainActivity extends BaseMvpActivity implements Contract.ContractView {

private Contract.ContractPresenter presenter = new PresenterIml(this);

@Override
public int getLayoutResId() {
return R.layout.activity_main;
}

@Override
public void initView() {

}

@Override
public void initData() {

}

@Override
protected BasePresenter bindPresenter() {
return presenter;
}

@Override
protected void onResume() {
super.onResume();
// 请求数据
if (presenter!=null)
presenter.startRequestData("","type");
}

@Override
public void showView(UserBean user) {
Log.e("TAG",user.toString());
}
}
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
public abstract class BaseMvpActivity extends BaseActivity  {
private BasePresenter presenter = null;
public Context mContext;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter = bindPresenter();
mContext = this;
}

/**
* 绑定presenter,主要用于销毁工作
*
* @return
*/
protected abstract BasePresenter bindPresenter();

/**
* 如果重写了此方法,一定要调用super.onDestroy();
*/
@Override
public void onDestroy() {
super.onDestroy();
if (presenter != null) {
presenter.onDestroy();
presenter = null;
System.gc();
}
}
}
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
public class PresenterIml implements Contract.ContractPresenter {
private Contract.ContractView contractView;
private Contract.ContractModel contractModel;

public PresenterIml(Contract.ContractView contractView) {
this.contractView = contractView;
contractModel =new ModelIml();
}

@Override
public void onDestroy() {
contractView = null;
System.gc();
}

@Override
public void startRequestData(String id, final String type) {
contractModel.getDataList(id,type, new BaseCallbackListener<UserBean>() {
@Override
public void onStart() {
//拿到结果之后判断v层是否已经销毁,防止空对象
if (contractView == null) {
return;
}
}

@Override
public void onNext(UserBean result) {
//拿到结果之后判断v层是否已经销毁,防止空对象
if (contractView == null) {
return;
}
switch (result.getCode()) {
case "200":
contractView.showView(result);
break;
case "500":

break;
default:
break;
}
}

@Override
public void onError(String str) {
//拿到结果之后判断v层是否已经销毁,防止空对象
if (contractView == null) {
return;
}
// 逻辑代码
}
});
}
}

一种方法,自动实现 String 和集合的非空判断。
Generate–>Getter and Setter–>Getter template–> ··· –> + –>添加如下代码;

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
#if($field.modifierStatic)
static ##
#end
$field.type ##
#set($name = $StringUtil.capitalizeWithJavaBeanConvention($StringUtil.sanitizeJavaIdentifier($helper.getPropertyName($field, $project))))
#if ($field.boolean && $field.primitive)
#if ($StringUtil.startsWithIgnoreCase($name, 'is'))
#set($name = $StringUtil.decapitalize($name))
#else
is##
#end
#else
get##
#end
${name}() {
#if ($field.string)
return $field.name == null ? "" : $field.name;
#else
#if ($field.list)
if ($field.name == null) {
return new ArrayList<>();
}
return $field.name;
#else
return $field.name;
#end
#end
}



// 使用上面规则生成的get方法,实现的效果如下;
public String getName() {
return name == null ? "" : name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public List<String> getmList() {
if (mList == null) {
return new ArrayList<>();
}
return mList;
}

public void setmList(List<String> mList) {
this.mList = mList;
}

备注

参考资料:

《Android Jetpack开发 原理解析与应用实战》

Android 进阶之光

传送门GitHub