本文不会讲解什么是MVP,如果还不太了解MVP请自行查阅资料,本文重点是封装一个高级MVP架构,会详细的讲解如何一步步从无到有的封装成一个高级MVP架构过程。
众所周知普通的MVP模式存在内存泄露、代码冗余、界面意外关闭后在重建数据缓存等问题,本文最终封装的成果为一一解决这些问题,而且在使用过程中尽量做到使用简单而且可扩展,当然本文也只是提供了一种封装思路而已,如果不能满足你的需求还可以自行再进行扩展。
如果你觉得你不想看整个实现思路可以直接看最后的源码,望给点个star鼓励一下
GitHub地址:https://github.com/ljqloveyou123
文章会以5个部分来整体优化封装MVP,也是一个从无到有的过程
一、不使用MVP的代码
二、最简单的MVP实现
三、解决MVP内存泄露
四、简单抽象-解决MVP代码冗余
五、高级抽象-使用注解、工厂模式、代理模式、策略模式整体解决代码冗余、内存泄露、Presenter生命周期以及数据存储问题
不废话了,进入正题。
场景:假如界面有一个按钮,点击后请求数据,然后成功后将返回的数据设置到一个Textview中
一、不使用MVP的代码,一般我们会这么写
public class MainActivity extends AppCompatActivity {
@FieldView(R.id.tv_text)
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewFind.bind(this);
}
//按钮点击事件
public void request(View view) {
clickRequest("101010100");
}
//发起请求
public void clickRequest(final String cityId) {
//请求接口
Retrofit retrofit = new Retrofit.Builder()
//代表root地址
.baseUrl("http://www.weather.com.cn/")
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService apiService = retrofit.create(ApiService.class);
//请求
Call<WeatherBean> weatherBeanCall = apiService.requestWeather(cityId);
weatherBeanCall.enqueue(new Callback<WeatherBean>() {
@Override
public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
//请求成功
textView.setText(response.body().getWeatherinfo().toString());
}
@Override
public void onFailure(Call<WeatherBean> call, Throwable t) {
//请求失败
}
});
}
}
上面的代码是最原始的写法,下面我们使用最简单的MVP模式来改造这个代码。
二、最简单的MVP实现
思路如下:
1、首先我们先定义一个接口,用来规定针对这个界面逻辑View需要作出的动作的接口。
2、让Activity实现这个接口中的方法,也就是V层
3、创建一个类,用来封装之前的网络请求过程,也就是M层
4、再创建一个类,用来处理M层和V层之间的通信,也就是P层
下面来实现一下:
1、首先我们先定义一个接口,用来规定针对这个界面逻辑View需要作出的动作的接口。
/**
* @author 刘镓旗
* @date 2017/11/16
* @description V层接口,定义V层需要作出的动作的接口
*/
public interface RequestView1 {
//请求时展示加载
void requestLoading();
//请求成功
void resultSuccess(WeatherBean result);
//请求失败
void resultFailure(String result);
}
2、让Activity实现这个接口中的方法,也就是V层
/**
* 第二步:对应demo1
* 2,最简单的mvp模式,
* 1.Activity需要实现v层接口
* 2.Persenter需要持有v层引用和m层引用
* 3.在实现类view中创建persenter
*
*/
public class MainActivity extends AppCompatActivity implements RequestView1 {
@FieldView(R.id.tv_text)
private TextView textView;
private RequestPresenter1 presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewFind.bind(this);
//创建Presenter
presenter = new RequestPresenter1(this);
}
//点击事件
public void request(View view) {
presenter.clickRequest("101010100");
}
//请求时加载
@Override
public void requestLoading() {
textView.setText("请求中,请稍后...");
}
//请求成功
@Override
public void resultSuccess(WeatherBean result) {
//成功
textView.setText(result.getWeatherinfo().toString());
}
//请求失败
@Override
public void resultFailure(String result) {
//失败
textView.setText(result);
}
}
3、创建一个类,用来封装之前的网络请求过程,也就是M层
/**
* @author 刘镓旗
* @date 2017/11/16
* @description M层 数据层
*/
public class RequestMode1 {
private static final String BASE_URL = "http://www.weather.com.cn/";
//http://www.weather.com.cn/data/cityinfo/101010100.html
public void request(String detailId, Callback<WeatherBean> callback){
//请求接口
Retrofit retrofit = new Retrofit.Builder()
//代表root地址
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService apiService = retrofit.create(ApiService.class);
//请求
Call<WeatherBean> weatherBeanCall = apiService.requestWeather(detailId);
weatherBeanCall.enqueue(callback);
}
}
4、再创建一个类,用来处理M层和V层之间的通信,也就是P层
/**
* @author 刘镓旗
* @date 2017/11/16
* @description P层
* 特点:需要持有M层和V层
*/
public class RequestPresenter1 {
private final RequestView1 mRequestView;
private final RequestMode1 mRequestMode;
public RequestPresenter1(RequestView1 requestView) {
this.mRequestView = requestView;
this.mRequestMode = new RequestMode1();
}
public void clickRequest(final String cityId){
//请求时显示加载
mRequestView.requestLoading();
//模拟耗时,可以展示出loading
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mRequestMode.request(cityId, new Callback<WeatherBean>() {
@Override
public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
mRequestView.resultSuccess(response.body());
}
@O