MVC MVP MVVM (图文):https://blog.csdn.net/jinmie0193/article/details/81531907
MVC MVP MVVM (代码):https://blog.csdn.net/jinmie0193/article/details/81536793
本文代码下载:https://download.csdn.net/download/jinmie0193/10641441
目录
简单介绍MVP
推荐github上的一个第三方库Mosby,通过这个库大家可以很轻松的实现MVP。
流程:
和MVC最大的不同,MVP把activity作为了view层,
view层activity没有任何和model层相关的逻辑代码,取而代之的是把代码放到了presenter层中,
presenter获取了model层的数据之后,通过接口的形式将view层需要的数据返回给它就OK了。
这样的好处是什么呢?
首先,activity的代码逻辑减少了
其次,view层和model层完全解耦,
如果你需要测试一个http请求是否顺利,你不需要写一个activity,只需要写一个java类,实现对应的接口,presenter获取了数据自然会调用相应的方法,
相应的,你也可以自己在presenter中mock(虚拟)数据,分发给view层,用来测试布局是否正确。
MVP实战
在现在的公司项目中,我已经用上了MVP模式开发。但是在这里,我不想照搬代码。主要是因为怕复杂的代码或者其它的知识点干扰MVP本身的脉络。所以,我用一个简单的DEMO来讲解,大家一看就明白。
场景需求
假设现在需要做一款APP,就是显示天气,界面很简单,一个TextView显示天气信息,一个Button用来请求实时天气。
软件启动后,会自动获取天气,然后TextView就可以显示信息。而用户点击获取实时天气的按钮,界面上会弹出正在获取中的进度对话框,等待数据加载成功后,对话框消失。Textview显示就新的天气情况。
MVP模式包的组织
View层的接口定义及实现
在MVP中Activity用来专注视图的表现。
而在本例子中View的表现有哪些呢?View的表现当然要用View.interface接口来定义
View层功能模块分析
1.更新天气
2.显示获取信息等待对话框
3.取消显示对话框
定义接口
public interface WeatherViewInterface {
/*更新天气*/
public void updateWeather(String info);
/*显示获取信息等待对话框*/
public void showWaitingDialog();
/*取消显示对话框*/
public void dissmissDialog();
}
实现接口
public class MainProgramEntry extends AppCompatActivity implements WeatherViewInterface {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_program_entry);
}
@Override
public void updateWeather(final String info) {
}
@Override
public void showWaitingDialog() {
}
@Override
public void dissmissDialog() {
}
}
具体的业务代码,我们等会再实现。
Model层的接口定义及实现
Model层是数据层,用来存储数据并且提供数据。在这里为了便于演示,数据被简化为了String类型。
Model层功能模块分析
1.提供数据
2.存储数据
定义接口
public interface WeatherModelInterface {
/*提供数据*/
public String getInfo();
/*存储数据*/
public void setInfo(String info);
}
实现接口
public class WeatherModel implements WeatherModelInterface {
private String weatherInfo;
@Override
public String getInfo() {
return weatherInfo;
}
@Override
public void setInfo(String info) {
weatherInfo = info;
}
}
Presenter代码及实现
Presenter是个大忙人,因为要同时对View和Model对接,所以内部必须持有它们的接口引用。
所以有如下:
public class WeatherPresenter {
WeatherViewInterface viewInterface;
WeatherModelInterface modelInterface;
}
Presenter与View的通信
1. View—–>Presenter
从视图界面出发,用户要请求数据,而Presenter是具体实现者,所以Presenter要提供方法代View的实现者调用,并且View的实现中必须要有Presenter的引用。
所以MainProgramEntry .java中要有WetherPresenter的引用。
public class MainProgramEntry extends AppCompatActivity implements WeatherViewInterface{
......
WeatherPresenter weatherPresenter;
......
}
而Presenter也要开发API供View调用。
所以Presenter要有requestWetherInfo()方法:
public class WetherPresenter {
WeatherViewInterface viewInterface;
WeatherModelInterface modelInterface;
/*供View层调用,用来请求天气数据*/
public void requestWeatherInfo(){
。。。。
}
}
2. presenter—–>View
presenter操作View,是通过View.interface,也就是View层定义的接口。
所以很容易得到下面的代码:
public class WetherPresenter {
......
private void showWaitDialog(){
if (viewInterface != null){
viewInterface.showWaitingDialog();
}
}
private void dissmissDialog(){
if (viewInterface != null){
viewInterface.dissmissDialog();
}
}
private void updateWeather(String info){
if (viewInterface != null){
viewInterface.updateWeather(info);
}
}
......
}
因为Presenter持有View的引用,所以在这里要将View.interface注入到Presenter当中。同时也需要实例化Model.interface,以便操作数据。
public class WetherPresenter {
WeatherViewInterface viewInterface;
WeatherModelInterface modelInterface;
......
public WeatherPresenter(WeatherViewInterface viewInterface){
this.viewInterface = viewInterface;
modelInterface = new WeatherModel();
}
......
}
Presenter与Model的通信
Presenter与Model的通信也是双方的。
3. Presenter—->Model
presenter获取到了数据,可以交给Model处理。
private void setInfo(String info){
modelInterface.setInfo(info);
}
4. Model—–>Presenter
Model处理完数据后它也能对Presenter提供数据。Presenter可以通过Model对象获取本地数据。
WetherPresenter.java
/*Model处理完数据后,它也能对Presenter提供数据*/
private String getInfo(){
return modelInterface.getInfo();
}
5. Presenter代码实现
前面已经讲了Presenter与Model,Presenter与View之间的通信,现在就可以编写代码将它们粘合起来。
Presenter本身需要向服务器获取代码,所以还要编写它的相应方法:
/*供View层调用,用来请求天气数据*/
public void requestWeatherInfo(){
getNetWorkInfo();
}
public void getNetWorkInfo(){
new Thread(new Runnable() {
@Override
public void run() {
try {
/*打开对话框*/
showWaitDialog();
/*模拟网络耗时*/
Thread.sleep(6000);
/*随机天气*/
String weatherInfo = "12度,多云";
Random r = new Random();
int seed = r.nextInt(3);
if(seed % 2 == 0){
weatherInfo = "21度,晴转多云";
}else{
weatherInfo = "22度,晴";
}
/*保存到model层*/
setInfo(weatherInfo);
/*从Model层获取数据*/
String localInfo = getInfo();
/*通知View层改变视图*/
updateWeather(localInfo);
}catch (Exception e){
e.printStackTrace();
}finally {
/*取消对话框*/
dissmissDialog();
}
}//run
}).start();
}
View层接口具体实现
1.生成Presenter。这个在Activity中的onCreate方法中,并把自身当成IWetherView注入到presenter当中。
/*把自身当成 WeatherViewInterface 注入到presenter当中*/
weatherPresenter = new WeatherPresenter(this);
2 . 操作Presenter。当用户点击按钮时,通过调用mPresenter获取数据,然后静待更新。
@OnClick({R.id.lable, R.id.tv_info, R.id.btn_request})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.lable:
break;
case R.id.tv_info:
break;
case R.id.btn_request:
/*用户点击按钮调用Presenter获取数据,然后静待更新*/
weatherPresenter.requestWeatherInfo();
break;
}
}
View.interface回调方法被触发时,进行相应的视图更新。
这里主要的视图有
显示对话框
取消对话框
显示 天气信息。
对应代码如下:
@Override
public void updateWeather(final String info) {
LogUtils.eTag("Liang","updateWeather: "+info);
runOnUiThread(new Runnable() {
@Override
public void run() {
tvInfo.setText(info);
}
});
}
@Override
public void showWaitingDialog() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mDialog != null && mDialog.isShowing()){
mDialog.dismiss();
}
mDialog = ProgressDialog.show(MainProgramEntry.this,"获取天气","正在获取...");
}
});
}
@Override
public void dissmissDialog() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if(mDialog != null && mDialog.isShowing()){
mDialog.dismiss();
}
}
});
}
效果如上面的:
总结
mvp非常适合大型的APP开发,越复杂它的优势越明显,但是如果APP代码本身很简明,mvp就有点绕弯子的感觉了