写点什么

从 0 到 1,带你解剖 MVP 的神秘之处,并自己动手实现 MVP !

用户头像
极客good
关注
发布于: 刚刚

脱离主工程独立运行,独立调试。这样就 i 使得在以后的版本维护及迭代中,


各个业务线的开发人员的职责更加明确。


各个模块之间还可以组合运行,能够及时适应产品的需求,灵活拆分组合打包上线。


目前应用较多的框架主要有:


阿里的 [ARouter](


)、


得到开源的 [DDComponentForAndroid](


)

[](

)5. 组件化


将通用的一个功能或 UI 库做成一个组件。


比如及时通讯、支付、分享、推送、下拉刷新等。


模块化是根据业务抽离,组件化是根据功能 UI 抽离。


一个模块可以依赖多个组件,组件与组件之间不可相互依赖。


[](


)MVP 具体实现




假设现在有这样一个需求,在某一个页面,当用户点击按钮,从网络获取数据并展示在当前页。


这是一个很简单的需求,让我们拆分一下,整理一下实现思路:


  • View:对应某一个页面,按钮的点击操作,属于和用户的交互

  • Model:对应从网络获取数据

  • Presenter:负责从 Model 获取数据,并回调给 ViewView 拿到数据后进行展示


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>() {


@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());


}


});


}


}


复制代码

[](

)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;


@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,敲完上面的代码,运行项目,点击获取,就会看到下面的界面:


https://user-gold-cdn.xitu.io/2018/8/16/16542259ac4108ba?imageView2/0/w/1280/h/960/format/webp/ignore-error/1


说明我们已经完成了最简单 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>() {


@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;


}


}


复制代码

[](

)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;


@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 进一步优化




写到这里,对于内存泄漏问题,我们已经完美的解决了。但对于整个 MVP 的实现,貌似还不是那么完美。


有什么问题呢?在上面的代码中,我们在 V 层实现了 Presenter 的绑定与解绑操作。但是,在实际应用开发


过程中,会有很多个涉及网络请求操作的 Activity,难不成每个 Activity 都要去实现重写绑定与解绑?


很明显,这样做是可以的!哈哈哈!但是出于对自己的严格要求以及对代码质量的不断追求,


显然,优化工作是一定要做的!那么,下面,我们的任务就是如何优化、如何扫除多余臃肿代码?

[](

)1. 创建一个抽象基类,BaseMVPActivity


提供 createPresenter(),并返回 Presenter 对象,这样拿到了子类的 Presenter


对象,就可以进行绑定解绑操作了。


public abstract class BaseMVPActivity<T extends IPresenter> extends AppCompatActivity implements IView {


protected T mPresenter;


@Override

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
从 0 到 1,带你解剖 MVP 的神秘之处,并自己动手实现 MVP !