对于新入门或者以及有过一段开发经验对 MVP 仍有困惑的 Android 开发者,这篇文章,但愿你不要错过。git
本文主要讲解了最基础 MVP ,从 0 到 1 的实现过程,以及如何解决实现过程当中遇到的问题。github
关于 Android 架构,目前主要有 MVC、MVP、MVVM、模块化、组件化等。数据库
M:逻辑模型,V:视图模型,C:控制器bash
但这种架构,相较于其余几种,比较落后。 并且耦合性严重,网络
职责相对不够明确不利于后期维护,架构
适用于小型的一次性项目。app
Model:包含具体的数据源以及数据请求框架
View:负责 UI 处理,对应 Activity、Fragmentide
Presenter:负责收取 View 发起的操做指令,并根据指令调用 Model 方法,模块化
获取数据, 并对获取的数据进行整合,再回调给 View。
目前 MVP 是应用比较普遍的一种架构,
层次清晰,耦合度下降,同时 View 只负责 UI 便可,释放了 View。
可是,在加入 Presenter 做为 View 和 Model 的桥梁的同时,
也致使了 Presenter 会愈来愈臃肿,也不利于后期的维护。
而且,每个包含网络请求的 View 都须要对应一个或多个 Presenter。
相对来讲,MVVM 其实是 MVP 的改进版,
将 Presenter 改成 ViewModel,并配合 Databinding,
经过双向数据绑定来实现视图与数据的交互。
MVVM 目前相较 MVP,应用较少,调试不够方便,
架构的实现方式不够完善,常见的只有 Databinding 框架,
中小型项目不适用用这种架构。但它简化了开发,数据和视图只须要绑定一次便可。
对一系列具备内聚性的业务进行整理,将其与其余业务进行切割、拆分,
从主工程或者原位置抽离为一个相对独立的部分。
不一样的模块之间,相互独立,不存在依赖与被依赖的关系。大大减小了耦合度。
既能够以 Library 的形式供主工程依赖,又能够以 Application 的形式,
脱离主工程独立运行,独立调试。这样就i使得在之后的版本维护及迭代中,
各个业务线的开发人员的职责更加明确。
各个模块之间还能够组合运行,可以及时适应产品的需求,灵活拆分组合打包上线。
目前应用较多的框架主要有:
阿里的 ARouter、
获得开源的 DDComponentForAndroid
将通用的一个功能或 UI 库作成一个组件。
好比及时通信、支付、分享、推送、下拉刷新等。
模块化是根据业务抽离,组件化是根据功能 UI 抽离。
一个模块能够依赖多个组件,组件与组件之间不可相互依赖。
假设如今有这样一个需求,在某一个页面,当用户点击按钮,从网络获取数据并展现在当前页。
这是一个很简单的需求,让咱们拆分一下,整理一下实现思路:
ok,思路有了,如今用代码进行实现:
/**
* 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);
}
}
复制代码
public interface DataView {
void getDataSuccess(List<ArticleBean> articleList);
void getDataFail(String failMsg);
}
复制代码
/**
* 负责 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>() {
@Override
public void onResponse(Call<BaseResponse> call, Response<BaseResponse> response) {
mView.getDataSuccess(response.body().getResult().getList());
}
@Override
public void onFailure(Call<BaseResponse> call, Throwable t) {
mView.getDataFail(t.getMessage());
}
});
}
}
复制代码
/**
* 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;
@Override
protected 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() {
@Override
public void onClick(View v) {
mPresenter.getData(APP_KEY);
}
});
}
@Override
public void getDataSuccess(List<ArticleBean> articleList) {
mAdapter.setNewData(articleList);
}
@Override
public void getDataFail(String failMsg) {
Toast.makeText(this, failMsg, Toast.LENGTH_SHORT).show();
}
}
复制代码
ok,敲完上面的代码,运行项目,点击获取,就会看到下面的界面:
说明咱们已经完成了最简单 MVP 的编写。
细心的同窗可能会发现,咱们在 DataPresenter 中持有了 V 层的引用。
这个问题就很严重了,若是在获取网络数据的时候,当前的 Activity 就被销毁了,那么就会引发内存泄漏。
如何避免呢?解决方法也很简单,只须要在 Activity 销毁时,将 V 层的引用置空不就能够了?
ok,思路有了,往下看代码实现:
public interface IPresenter {
void attach(DataView dataView);
void detach();
}
复制代码
/**
* 负责 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>() {
@Override
public void onResponse(Call<BaseResponse> call, Response<BaseResponse> response) {
mView.getDataSuccess(response.body().getResult().getList());
}
@Override
public void onFailure(Call<BaseResponse> call, Throwable t) {
mView.getDataFail(t.getMessage());
}
});
}
@Override
public void attach(DataView dataView) {
this.mView = dataView;
}
@Override
public void detach() {
this.mView = null;
}
}
复制代码
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;
@Override
protected 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() {
@Override
public void onClick(View v) {
mPresenter.getData(APP_KEY);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
mPresenter.detach();
}
@Override
public void getDataSuccess(List<ArticleBean> articleList) {
mAdapter.setNewData(articleList);
}
@Override
public void getDataFail(String failMsg) {
Toast.makeText(this, failMsg, Toast.LENGTH_SHORT).show();
}
}
复制代码
写到这里,对于内存泄漏问题,咱们已经完美的解决了。但对于整个 MVP 的实现,貌似还不是那么完美。
有什么问题呢?在上面的代码中,咱们在 V 层实现了 Presenter 的绑定与解绑操做。可是,在实际应用开发
过程当中,会有不少个涉及网络请求操做的 Activity,难不成每一个 Activity 都要去实现重写绑定与解绑?
很明显,这样作是能够的!哈哈哈!可是出于对本身的严格要求以及对代码质量的不断追求,
显然,优化工做是必定要作的!那么,下面,咱们的任务就是如何优化、如何扫除多余臃肿代码?
提供 createPresenter(),并返回 Presenter 对象,这样拿到了子类的 Presenter
对象,就能够进行绑定解绑操做了。
public abstract class BaseMVPActivity<T extends IPresenter> extends AppCompatActivity implements IView {
protected T mPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(createView());
mPresenter = createPresenter();
if (null == mPresenter) {
throw new IllegalStateException("Please call mPresenter in BaseMVPActivity(createPresenter) to create!");
} else {
mPresenter.attach(this);
}
viewCreated();
}
protected abstract void viewCreated();
@Override
protected void onDestroy() {
super.onDestroy();
if (null != mPresenter){
mPresenter.detach();
}
}
protected abstract int createView();
protected abstract T createPresenter();
@Override
public void showLoading() {
}
@Override
public void hideLoading() {
}
}
复制代码
public class BasePresenter<V extends IView> implements IPresenter<V> {
protected V view;
@Override
public void attach(V view) {
this.view = view;
}
@Override
public void detach() {
this.view = null;
}
}
复制代码
public interface IView {
void showLoading();
void hideLoading();
}
复制代码
修改以后的 Activity:
/**
* View 层,负责 UI 绘制以及与用户的交互
*/
public class MVPDemoAty extends BaseMVPActivity<DataPresenter> implements DataView {
private static final String APP_KEY = "dbb6893ab0913b02724696504181fe39";
private Button btnGet;
private RecyclerView recyclerView;
private DataAdapter mAdapter;
private ProgressDialog mDialog;
@Override
protected void viewCreated() {
mDialog = new ProgressDialog(this);
mDialog.setMessage("玩命加载中...");
btnGet = findViewById(R.id.btnGet);
recyclerView = findViewById(R.id.recyclerView);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
// linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(linearLayoutManager);
mAdapter = new DataAdapter(this, new ArrayList<ArticleBean>());
recyclerView.setAdapter(mAdapter);
btnGet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDialog.show();
mPresenter.getData(APP_KEY);
}
});
}
@Override
protected int createView() {
return R.layout.activity_mvp_demo;
}
@Override
protected DataPresenter createPresenter() {
return new DataPresenter();
}
@Override
public void getDataSuccess(List<ArticleBean> articleList) {
mDialog.dismiss();
mAdapter.setNewData(articleList);
}
@Override
public void getDataFail(String failMsg) {
mDialog.dismiss();
Toast.makeText(this, failMsg, Toast.LENGTH_SHORT).show();
}
}
复制代码
到此,一个较完善的 MVP 架构,已经实现的差很少了。上面实现的是 Activity 的MVP实现,
Fragment 也是同样,在这里就不实现了。固然,对于上面实现的 MVP 仍然还有不少能够优化之处,
时间有限,就先实现到这里,之后有时间再改造。最后,附上 Github 下载地址: