从 0 到 1,带你解剖 MVP 的神秘之处,并自己动手实现 MVP !
层次清晰,耦合度降低,同时 View 只负责 UI 即可,释放了 View。
但是,在加入 Presenter 作为 View 和 Model 的桥梁的同时,
也导致了 Presenter 会越来越臃肿,也不利于后期的维护。
并且,每一个包含网络请求的 View 都需要对应一个或多个 Presenter。
3. MVVM: Model - View - ViewModel
相对来说,MVVM 实际上是 MVP 的改进版,
将 Presenter 改为 ViewModel,并配合 Databinding,
通过双向数据绑定来实现视图与数据的交互。
MVVM 目前相较 MVP,应用较少,调试不够方便,
架构的实现方式不够完善,常见的只有 Databinding 框架,
中小型项目不适用用这种架构。但它简化了开发,数据和视图只需要绑定一次即可。
4. 模块化:独立、解耦、可重性
对一系列具有内聚性的业务进行整理,将其与其他业务进行切割、拆分,
从主工程或者原位置抽离为一个相
对独立的部分。
不同的模块之间,相互独立,不存在依赖与被依赖的关系。大大减少了耦合度。
既可以以 Library 的形式供主工程依赖,又可以以 Application 的形式,
脱离主工程独立运行,独立调试。这样就 i 使得在以后的版本维护及迭代中,
各个业务线的开发人员的职责更加明确。
各个模块之间还可以组合运行,能够及时适应产品的需求,灵活拆分组合打包上线。
目前应用较多的框架主要有:
阿里的 [ARouter](
)、
得到开源的 [DDComponentForAndroid](
)
5. 组件化
将通用的一个功能或 UI 库做成一个组件。
比如及时通讯、支付、分享、推送、下拉刷新等。
模块化是根据业务抽离,组件化是根据功能 UI 抽离。
一个模块可以依赖多个组件,组件与组件之间不可相互依赖。
MVP 具体实现
假设现在有这样一个需求,在某一个页面,当用户点击按钮,从网络获取数据并展示在当前页。
这是一个很简单的需求,让我们拆分一下,整理一下实现思路:
View:对应某一个页面,按钮的点击操作,属于和用户的交互
Model:对应从网络获取数据
Presenter:负责从 Model 获取数据,并回调给 View,View 拿到数据后进行展示
ok,思路有了,现在用代码进行实现:
1. 创建 Model 类,封装通过网络请求获取数据的过程,即 M 层
/**
model 层:从数据源(网络、数据库)获取数据*/public class DataModel {
private DataApi mApi;
public DataModel() {mApi = RetrofitHelpter.createApi(DataApi.class);}
public void getData(String appKey, Callback<BaseResponse> callback) {Call<BaseResponse> responseCall = mApi.getData(appKey);// 发起请求 responseCall.enqueue(callback);}
}
2. 在创建 Presenter 层之前,我们需要创建一个接口,取名 DataView,负责向 V 层回调数据
public interface DataView {
void getDataSuccess(List<ArticleBean> articleList);
void getDataFail(String failMsg);
}
3. 现在创建 Presenter,取名 DataPresenter
/**
负责 View 层和 Model 层之间的通信,并对从 Model 层获取的数据进行处理*/public class DataPresenter {
private DataView mView;private DataModel mModel;
public DataPresenter(DataView dataView) {this.mView = dataView;this.mModel = new DataModel();}
/**
定义 View 层需要进行的 action*/public void getData(String appKey) {mModel.getData(appKey, new Callback<BaseResponse>() {@Overridepublic void onResponse(Call<BaseResponse> call, Response<BaseResponse> response) {mView.getDataSuccess(response.body().getResult().getList());}
@Overridepublic void onFailure(Call<BaseResponse> call, Throwable t) {mView.getDataFail(t.getMessage());}});}
}
4. 在我们的 View 层,实现 DataView 接口,并重写方法,这样就能接收到回调数据了
/**
View 层,负责 UI 绘制以及与用户的交互*/public class MVPDemoAty extends AppCompatActivity implements DataView {
private static final String APP_KEY = "dbb6893ab0913b02724696504181fe39";
private Button btnGet;private RecyclerView recyclerView;
private DataPresenter mPresenter;
private DataAdapter mAdapter;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_mvp_demo);
btnGet = findViewById(R.id.btnGet);recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
mPresenter = new DataPresenter(this);
mAdapter = new DataAdapter(this, new ArrayList<ArticleBean>());recyclerView.setAdapter(mAdapter);
btnGet.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mPresenter.getData(APP_KEY);}});
}
@Overridepublic void getDataSuccess(List<ArticleBean> articleList) {mAdapter.setNewData(articleList);}
@Overridepublic void getDataFail(String failMsg) {Toast.makeText(this, failMsg, Toast.LENGTH_SHORT).show();}}
ok,敲完上面的代码,运行项目,点击获取,就会看到下面的界面:
说明我们已经完成了最简单 MVP 的编写。
MVP 解决内存泄漏
细心的同学可能会发现,我们在 DataPresenter 中持有了 V 层的引用。
这个问题就很严重了,如果在获取网络数据的时候,当前的 Activity 就被销毁了,那么就会引起内存泄漏。
如何避免呢?解决方法也很简单,只需要在 Activity 销毁时,将 V 层的引用置空不就可以了?
ok,思路有了,往下看代码实现:
1. 编写 IPresenter 接口,提供绑定和解绑两个方法
public interface IPresenter {
void attach(DataView dataView);
void detach();
}
2. DataPresenter 类实现 IPresenter
/**
负责 View 层和 Model 层之间的通信,并对从 Model 层获取的数据进行处理*/public class DataPresenter implements IPresenter {
private DataView mView;private DataModel mModel;
public DataPresenter() {this.mModel = new DataModel();}
/**
定义 View 层需要进行的 action*/public void getData(String appKey) {mModel.getData(appKey, new Callback<BaseResponse>() {@Overridepublic void onResponse(Call<BaseResponse> call, Response<BaseResponse> response) {mView.getDataSuccess(response.body().getResult().getList());}
@Overridepublic void onFailure(Call<BaseResponse> call, Throwable t) {mView.getDataFail(t.getMessage());}});}
@Overridepublic void attach(DataView dataView) {this.mView = dataView;}
@Overridepublic void detach() {this.mView = null;}}
3. 在 V 层中,创建 Presenter 完成之后,就绑定mPresenter.attach(this);
,
并在销毁时,调用 mPresenter.detach();
修改后的代码如下:
/**
View 层,负责 UI 绘制以及与用户的交互*/public class MVPDemoAty extends AppCompatActivity implements DataView {
private static final String APP_KEY = "dbb6893ab0913b02724696504181fe39";
private Button btnGet;private RecyclerView recyclerView;
private DataPresenter mPresenter;
private DataAdapter mAdapter;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_mvp_demo);
btnGet = findViewById(R.id.btnGet);recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
mPresenter = new DataPresenter();mPresenter.attach(this);
mAdapter = new DataAdapter(this, new ArrayList<ArticleBean>());recyclerView.setAdapter(mAdapter);
btnGet.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mPresenter.getData(APP_KEY);}});
}
@Overrideprotected void onDestroy() {super.onDestroy();mPresenter.detach();}
@Override
评论