******再度回头看看安卓的MVP开发模式的总结******
1. 概述
MVP(Model - View - Presenter):即 模型 - 视图 - 协调者的简写,MVP是从经典的MVC模式中演变而来的,基本逻辑上是有相通之处。Model负责提供数据源,View负责数据的展示,Presenter负责主要业务逻辑的处理,将Model和View进行联系起来,完全把Model和View进行了彻底的分离,而Presenter与具体的View是没有直接关联的,而是通过定义好了的接口进行交互的,从而使得在变更View时候可保持Presenter的不变,即重用性。也可更好的模拟单元测试。
2. 架构及图解
![]() |
Model:即模型层,负责存储,检索以及操纵数据。
View:即视图层,负责绘制UI,与用户进行交互(Activity / Fragment)。
Presenter:即协调者(中间者),作为View与Model之间交互的中间纽带,负责处理与用户交互的主要业务逻辑。
3. 优缺点
优点:
① 复杂的业务逻辑处理都在Presenter中进行处理,从而减少了Activity的臃肿。
② Model层与View层完全彻底分离,修改View层不会对Model层受到影响,降低了之间的耦合性。
③ 可将一个Presenter用于一个或多个视图,从而无需改变Presenter的业务逻辑。
④ Presenter层与View层的交互是通过接口来进行的,从而便于单元测试。
缺点:
由于对视图View的渲染都在Presenter中定义,所以视图View和Presenter之间的交互会过于频繁,视图若需要改变,一般Presenter也需要跟随着变更。
4. 案例说明
请求接口的数据来源于 https://www.avatardata.cn/Docs/Api/5bc6f2a4-927c-415f-80ae-8772b76c8c73
有请求次数的限制,所以需要使用的,可自行注册账号,进行测试使用。
可以使用AndroidMVP插件来生成MVP的模板或者自己动手创建。
案例①

M层
/**
* 数据接口层.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public interface IAphorismsAModel {
/**
* 请求网络获取数据列表
*
* @param page 页码
* @param rows 一次请求返回多少数据
* @param callBack 回调函数
*/
public void getListData(int page, int rows, CallBack callBack);
}
/**
* 数据实现层.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public class AphorismsAModelImpl implements IAphorismsAModel {
/**
* 请求网络获取数据列表
*
* @param page 页码
* @param rows 一次请求返回多少数据
* @param callBack 回调函数
*/
@Override
public void getListData(int page, int rows, final CallBack callBack) {
String key = "9d3ce9c83fcd4c418dce2937c29b6414";
String param = "key=" + key + "&keyword=天才&page=" + page + "&rows=" + rows;
String url = "http://api.avatardata.cn/MingRenMingYan/LookUp?" + param;
OkHttpUtils.get()
.url(url)
.build()
.execute(new StringCallback() {
@Override
public void onResponse(String response, int id) {
GsonUtils utils = GsonUtils.getInstance();
AphorismsEntity aphorismsEntity = utils.fromJson(response, AphorismsEntity.class);
if (aphorismsEntity != null) {
callBack.onSuccess(aphorismsEntity.getResult());
} else {
callBack.onError(response);
}
}
@Override
public void onError(Call call, Exception e, int id) {
callBack.onError(e.getMessage());
}
});
}
}
V层
/**
* 视图接口.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public interface IAphorismsAView {
// 请求标记
public int REQUEST_ONE = 0;
public int REQUEST_TWO = 1;
public int REQUEST_THREE = 2;
// 响应标记
public int RESPONSE_SUCCESS = 200;
public int RESPONSE_ERROR = 404;
public int RESPONSE_FAILURE = 500;
public <T> T request(int requestFlag);
/**
* 请求返回的数据
*
* @param response
* @param responseFlag
* @param <T>
*/
public <T> void response(T response, int responseFlag);
/**
* 显示网络加载框
*/
public void showLoading();
/**
* 隐藏网络加载框
*/
public void dismissLoading();
/**
* 弹出提示
*
* @param msg
*/
public void showToast(String msg);
}
/**
* 显示名言警句.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public class AphorismsActivity extends AppCompatActivity implements IAphorismsAView {
private SmartRefreshLayout mSmartRefreshLayout;
private RecyclerView rcyAphorisms;
private LoadingDialog loadingDialog;
private AphorismsAdapter aphorismsAdapter;
private IAphorismsAPresenter mIAphorismsAPresenter;
private List<AphorismsEntity.ResultBean> resultBeanList = new ArrayList<>();
private int page = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mIAphorismsAPresenter = new AphorismsAPresenterImpl(this);
setContentView(R.layout.activity_aphorisms);
mSmartRefreshLayout = findViewById(R.id.refresh_layout);
rcyAphorisms = findViewById(R.id.rcy_aphorisms);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
rcyAphorisms.setLayoutManager(layoutManager);
rcyAphorisms.setHasFixedSize(true);
rcyAphorisms.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
rcyAphorisms.setItemAnimator(new DefaultItemAnimator());
aphorismsAdapter = new AphorismsAdapter(this);
rcyAphorisms.setAdapter(aphorismsAdapter);
// item的点击事件
aphorismsAdapter.setOnItemClickListener(new AphorismsAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
showToast(aphorismsAdapter.getData().get(position).getFamous_name());
}
});
// 获取电影列表数据
mIAphorismsAPresenter.getListData(1, 10);
// 刷新数据
mSmartRefreshLayout.setOnMultiPurposeListener(new SimpleMultiPurposeListener() {
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
super.onRefresh(refreshLayout);
runOnUiThread(new Runnable() {
@Override
public void run() {
page = 1;
mIAphorismsAPresenter.getListData(1, 10);
mSmartRefreshLayout.finishRefresh();
}
});
}
@Override
public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
super.onLoadMore(refreshLayout);
runOnUiThread(new Runnable() {
@Override
public void run() {
mIAphorismsAPresenter.getListData(++page, 10);
}
});
}
});
}
@Override
public <T> T request(int requestFlag) {
return null;
}
@Override
public <T> void response(T response, int responseFlag) {
if (responseFlag == IAphorismsAView.RESPONSE_SUCCESS) {
List<AphorismsEntity.ResultBean> list = (List<AphorismsEntity.ResultBean>) response;
if (list != null && list.size() > 0) {
resultBeanList.addAll(list);
aphorismsAdapter.addData(resultBeanList);
mSmartRefreshLayout.finishLoadMore();
} else {
showToast("数据已加载完毕");
// 将不会再次触发加载更多事件
mSmartRefreshLayout.finishLoadMoreWithNoMoreData();
mSmartRefreshLayout.resetNoMoreData();
}
}
}
@Override
public void showLoading() {
loadingDialog = new LoadingDialog(this);
loadingDialog.setLoadingText("加载中...");
loadingDialog.show();
}
@Override
public void dismissLoading() {
if (loadingDialog != null) {
loadingDialog.close();
}
}
@Override
public void showToast(String msg) {
Toast.makeText(this, "mvp: " + msg, Toast.LENGTH_SHORT).show();
}
}
P层
/**
* 逻辑接口层.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public interface IAphorismsAPresenter {
/**
* 请求网络获取数据列表
*
* @param page 页码
* @param rows 一次请求返回多少数据
*/
public void getListData(int page, int rows);
}
/**
* 逻辑实现层.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public class AphorismsAPresenterImpl implements IAphorismsAPresenter {
private IAphorismsAView mIAphorismsAView;
private IAphorismsAModel mIAphorismsAModel;
public AphorismsAPresenterImpl(IAphorismsAView aIAphorismsAView) {
mIAphorismsAView = aIAphorismsAView;
mIAphorismsAModel = new AphorismsAModelImpl();
}
/**
* 请求网络获取数据列表
*
* @param page 页码
* @param rows 一次请求返回多少数据
*/
@Override
public void getListData(int page, int rows) {
if (mIAphorismsAView == null) {
return;
}
mIAphorismsAView.showLoading();
mIAphorismsAModel.getListData(page, rows, new CallBack() {
@Override
public void onSuccess(Object response) {
mIAphorismsAView.dismissLoading();
mIAphorismsAView.response(response, mIAphorismsAView.RESPONSE_SUCCESS);
mIAphorismsAView.showToast("数据加载成功!");
}
@Override
public void onError(String error) {
mIAphorismsAView.dismissLoading();
mIAphorismsAView.response(error, mIAphorismsAView.RESPONSE_ERROR);
mIAphorismsAView.showToast("数据加载失败!");
}
});
}
}
/**
* 泛型类的回调接口
*
* @param <T>
*/
public interface CallBack<T> {
void onSuccess(T response);
void onError(String error);
}
案例②
对MVP模式的优化处理。因为在Presenter层持有了View层的强引用,若在请求结束之前,Activity(即View层)被销毁了,但是此时网络请求的数据还没有返回来,从而导致了Presenter一直持有Activity对象,使得Activity对象无法被收回,所以此时就发生了内存的这么一个泄露事件。所以,这里通过弱引用的一个方式来解决。

创建了一个Base包
/**
* Presenter基类(优化MVP模式, 这里采用弱引用的方式, 防止内存泄露).
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public abstract class BasePresenter<T> {
/**
* 声明一个View接口类型的弱引用
*/
protected Reference<T> mViewRef;
/**
* 与View建立关联
*
* @param view
*/
public void attachView(T view) {
mViewRef = new WeakReference<>(view);
}
/**
* 获取View对象
*
* @return
*/
protected T getView() {
return mViewRef.get();
}
/**
* 判断是否与View建立起关联
*
* @return
*/
public boolean isViewAttached() {
return mViewRef != null && mViewRef.get() != null;
}
/**
* 解除与View的关联, 避免内存泄露事件的发生
*/
public void detachView() {
if (mViewRef != null) {
mViewRef.clear();
mViewRef = null;
}
}
}
/**
* MvpActivity基类.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public abstract class BaseMvpActivity<V, T extends BasePresenter<V>> extends AppCompatActivity {
/**
* Presenter对象
*/
protected T mPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 创建Presenter对象
mPresenter = createPresenter();
// 将View与Presenter对象建立起关联
mPresenter.attachView((V) this);
}
/**
* 创建Presenter
*
* @return
*/
protected abstract T createPresenter();
/**
* 销毁View的关联
*/
@Override
protected void onDestroy() {
super.onDestroy();
mPresenter.detachView();
}
}
M层
/**
* 数据接口层.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public interface IAphorismsAModel {
/**
* 请求网络获取数据列表
*
* @param page 页码
* @param rows 一次请求返回多少数据
* @param callBack 回调函数
*/
public void getListData(int page, int rows, CallBack callBack);
}
/**
* 数据实现层.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public class AphorismsAModelImpl implements IAphorismsAModel {
/**
* 请求网络获取数据列表
*
* @param page 页码
* @param rows 一次请求返回多少数据
* @param callBack 回调函数
*/
@Override
public void getListData(int page, int rows, final CallBack callBack) {
String param = "key=9d3ce9c83fcd4c418dce2937c29b6414&keyword=天才&page=" + page + "&rows=" + rows;
String url = "http://api.avatardata.cn/MingRenMingYan/LookUp?" + param;
OkHttpUtils.get()
.url(url)
.build()
.execute(new StringCallback() {
@Override
public void onResponse(String response, int id) {
GsonUtils utils = GsonUtils.getInstance();
AphorismsEntity aphorismsEntity = utils.fromJson(response, AphorismsEntity.class);
if (aphorismsEntity != null) {
callBack.onSuccess(aphorismsEntity.getResult());
} else {
callBack.onError(response);
}
}
@Override
public void onError(Call call, Exception e, int id) {
callBack.onError(e.getMessage());
}
});
}
}
V层
/**
* 视图接口.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public interface IAphorismsAView {
// 请求标记
public int REQUEST_ONE = 0;
public int REQUEST_TWO = 1;
public int REQUEST_THREE = 2;
// 响应标记
public int RESPONSE_SUCCESS = 200;
public int RESPONSE_ERROR = 404;
public int RESPONSE_FAILURE = 500;
public <T> T request(int requestFlag);
/**
* 请求返回的数据
*
* @param response
* @param responseFlag
* @param <T>
*/
public <T> void response(T response, int responseFlag);
/**
* 显示网络加载框
*/
public void showLoading();
/**
* 隐藏网络加载框
*/
public void dismissLoading();
/**
* 弹出提示
*
* @param msg
*/
public void showToast(String msg);
}
/**
* 显示名言警句.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public class AphorismsActivity extends BaseMvpActivity<IAphorismsAView, AphorismsAPresenterImpl> implements IAphorismsAView {
private SmartRefreshLayout mSmartRefreshLayout;
private RecyclerView rcyAphorisms;
private LoadingDialog loadingDialog;
private AphorismsAdapter aphorismsAdapter;
private List<AphorismsEntity.ResultBean> resultBeanList = new ArrayList<>();
private int page = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aphorisms);
mSmartRefreshLayout = findViewById(R.id.refresh_layout);
rcyAphorisms = findViewById(R.id.rcy_aphorisms);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
rcyAphorisms.setLayoutManager(layoutManager);
rcyAphorisms.setHasFixedSize(true);
rcyAphorisms.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
rcyAphorisms.setItemAnimator(new DefaultItemAnimator());
aphorismsAdapter = new AphorismsAdapter(this);
rcyAphorisms.setAdapter(aphorismsAdapter);
// item的点击事件
aphorismsAdapter.setOnItemClickListener(new AphorismsAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
showToast(aphorismsAdapter.getData().get(position).getFamous_name());
}
});
// 获取电影列表数据
mPresenter.getListData(1, 10);
// 刷新数据
mSmartRefreshLayout.setOnMultiPurposeListener(new SimpleMultiPurposeListener() {
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
super.onRefresh(refreshLayout);
runOnUiThread(new Runnable() {
@Override
public void run() {
page = 1;
mPresenter.getListData(1, 10);
mSmartRefreshLayout.finishRefresh();
}
});
}
@Override
public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
super.onLoadMore(refreshLayout);
runOnUiThread(new Runnable() {
@Override
public void run() {
mPresenter.getListData(++page, 10);
}
});
}
});
}
@Override
protected AphorismsAPresenterImpl createPresenter() {
return new AphorismsAPresenterImpl();
}
@Override
public <T> T request(int requestFlag) {
return null;
}
@Override
public <T> void response(T response, int responseFlag) {
if (responseFlag == IAphorismsAView.RESPONSE_SUCCESS) {
List<AphorismsEntity.ResultBean> list = (List<AphorismsEntity.ResultBean>) response;
if (list != null && list.size() > 0) {
resultBeanList.addAll(list);
aphorismsAdapter.addData(resultBeanList);
mSmartRefreshLayout.finishLoadMore();
} else {
showToast("数据已加载完毕");
// 将不会再次触发加载更多事件
mSmartRefreshLayout.finishLoadMoreWithNoMoreData();
mSmartRefreshLayout.resetNoMoreData();
}
}
}
@Override
public void showLoading() {
loadingDialog = new LoadingDialog(this);
loadingDialog.setLoadingText("加载中...");
loadingDialog.show();
}
@Override
public void dismissLoading() {
if (loadingDialog != null) {
loadingDialog.close();
}
}
@Override
public void showToast(String msg) {
Toast.makeText(this, "mvp: " + msg, Toast.LENGTH_SHORT).show();
}
}
P层
/**
* 逻辑接口层.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public interface IAphorismsAPresenter {
/**
* 请求网络获取数据列表
*
* @param page 页码
* @param rows 一次请求返回多少数据
*/
public void getListData(int page, int rows);
}
/**
* 逻辑实现层.
*
* @author luyh
* @version 1.0
* @date 2019/04/08
*/
public class AphorismsAPresenterImpl extends BasePresenter<IAphorismsAView> implements IAphorismsAPresenter {
private IAphorismsAModel mIAphorismsAModel;
public AphorismsAPresenterImpl() {
mIAphorismsAModel = new AphorismsAModelImpl();
}
/**
* 请求网络获取数据列表
*
* @param page 页码
* @param rows 一次请求返回多少数据
*/
@Override
public void getListData(int page, int rows) {
getView().showLoading();
mIAphorismsAModel.getListData(page, rows, new CallBack() {
@Override
public void onSuccess(Object response) {
getView().dismissLoading();
getView().response(response, IAphorismsAView.RESPONSE_SUCCESS);
getView().showToast("数据加载成功!");
}
@Override
public void onError(String error) {
getView().dismissLoading();
getView().response(error, IAphorismsAView.RESPONSE_ERROR);
getView().showToast("数据加载失败!");
}
});
}
}
/**
* 泛型类的回调接口
*
* @param <T>
*/
public interface CallBack<T> {
void onSuccess(T response);
void onError(String error);
}
以下是两个案例中的源代码:
① 链接:https://pan.baidu.com/s/1tP38gO-xPYntaEszvme2IQ 提取码:u59t
② 链接:https://pan.baidu.com/s/1Nt9XNc0Ye651Mfnb6Kfwhg 提取码:n92w
两个案例的区别:
①中,使用的是常规的MVP模式做的;
②中,对MVP模式进行了优化处理,使用弱引用的方式对其进行了处理,防止内存泄漏。
本文介绍了Android的MVP开发模式,包括概述、架构、优缺点。MVP模式通过Model、View、Presenter三层分离,降低了组件间的耦合,提高了代码复用性。然而,频繁的View和Presenter交互可能导致过度紧密的联系,需要谨慎处理。


569

被折叠的 条评论
为什么被折叠?



