MVP:
Model:模型层,处理数据之类,如数据库操作,访问网络等。
View:视图层,xml布局文件及Activity、fragment。
Presenter:Presenter表示器(也称主持人),通过调用V、M层的接口来连接Model与View.
先了解一下MVC模式,MVC模式中Activity对应了MVC中的V和C,同时担任两个角色,会导致Activity过于复杂臃肿,因为MVC中是允许Model和View进行交互的. 例如在Activity中进行网络操作,得到数据后就设置在TextView中。
而MVP中很明显,Model与View之间的交互由Presenter完成。即在另一个类中执行访问网络的操作,得到数据后通过Pesenter类调用Activity的接口,这样Activity就获得了数据,然后再根据数据执行更新UI的操作。
Presenter与View之间,Presenter与Model之间的交互是通过接口的方式来进行的。简而言之即Model层与View层不直接交互,而是通过Presenter来处理。Model层声明接口、View层声明接口提供给Presenter调用来间接实现M层与V层的交互,Presenter也提供一些方法供View、Model层调用。
MVC、MVP模式区别如下图所示:
二:操作流程
(示例:点击按钮获取天气信息,然后显示在TextView中。)
1.M层:
#声明接口来表示M层要执行的动作,如数据库的操作有存储数据和获取数据这两个操作,即可在接口中声明抽象方法来表示这些动作,如:
public interface IWeatherModel {
public abstract void setInfo(String info);//设置数据
public abstract String getInfo();//获取数据
}
#创建接口的实现类,重写接口中的抽象方法,在里面执行具体的操作。(Presenter会调用里面的方法)如:
public class WeatherModel implements IWeatherModel {
private String mString;
@Override
public void setInfo(String info) {
mString=info;
}
@Override
public String getInfo() {
return mString;
}
}
2.V层:
#(与M层类似)声明接口来表示View层要执行的动作,如下面这个界面:
它要执行的操作包括3个: &当点击按钮时出现正在加载的Toast。
&当获取到天气信息之后将数据展示在TextView中。
&数据获取成功后出现加载完成的Toast。
所以就声明一个接口并创建三个抽象方法来表示这些操作,如:
public interface IWeatherView {
public abstract void showToast();
public abstract void dismissToast();
public abstract void setWeatherInfo(String info);
}
#创建接口的实现类(以上界面是看得见的,所以实现类是Activity,也可是fragment),重写接口中的抽象方法,在里面执行具体的操作。(Presenter会调用里面的方法)如:
public class MainActivity extends AppCompatActivity implements IWeatherView{//实现接口
private Button mButton;
private TextView mTextView;
private WeatherPresenter mWeatherPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton=findViewById(R.id.button);
mTextView=findViewById(R.id.textView);
mWeatherPresenter=new WeatherPresenter(this);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mWeatherPresenter.requestWeatherInfo();
}
});
}
/*重写接口中的抽象方法*/<------这一步只需看这里
@Override
public void showToast() {//因为此方法在WeatherPresenter中是在子线程中调用的,所有要进行UI操作需回到UI线程。
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"正在加载···",Toast.LENGTH_SHORT).show();
}
});
}
/*重写接口中的抽象方法*/<------这一步只需看这里
@Override
public void dismissToast() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"加载完成",Toast.LENGTH_SHORT).show();
}
});
}
/*重写接口中的抽象方法*/<------这一步只需看这里
@Override
public void setWeatherInfo(final String info) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText(info);
}
});
}
}
3.P层:
#创建一个类作为Presenter,然后创建V、M层的接口的实现类的对象(也可叫做接口的引用,不能叫接口的对象,因为接口不能创建对象),以此来调用接口中的方法。如:
public class WeatherPresenter {<------这一步只需看这里
private IWeatherView mIWeatherView;//接口的引用<------这一步只需看这里
private IWeatherModel mIWeatherModel;//接口的引用<------这一步只需看这里
public WeatherPresenter(IWeatherView mIWeatherView){<------这一步只需看这里
this.mIWeatherView=mIWeatherView;//初始化接口的引用<------这一步只需看这里
mIWeatherModel=new WeatherModel();//初始化接口的引用<------这一步只需看这里
}
public void requestWeatherInfo(){
new Thread(new Runnable() {
@Override
public void run() {
mIWeatherView.showToast();
try {
Thread.sleep(4000);
String info="21° 阴";
mIWeatherModel.setInfo(info);
String weather=mIWeatherModel.getInfo();
mIWeatherView.setWeatherInfo(weather);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
mIWeatherView.dismissToast();
}
}
}).start();
}
}
上面代码:声明一个Presenter类的构造方法(如下面代码),在里面初始化接口的引用,因为要使用接口的方法,需创建接口的实现类的对象。至于构造方法中传入一个View层接口IWeatherView的引用。是因为这里是MainActivity实现的View层的接口,所以无法创建Activity的对象,那么就在MainActivity中使用Presneter的构造方法并把this传入,这样Presneter类中就能初始化View层接口的引用。
public WeatherPresenter(IWeatherView mIWeatherView){
this.mIWeatherView=mIWeatherView;
mIWeatherModel=new WeatherModel();
}
#可以在presenter类中提供一些方法供View层和Model层调用,如这里声明一个requestWeatherInfo方法(如下面代码),就是提供给MainActivity用的,当点击按钮时就从Model层中获取数据,而View层不能和Model层直接联系,所以通过Prenenter类中的方法间接与Model联系。
public void requestWeatherInfo(){
new Thread(new Runnable() {
@Override
public void run() {
mIWeatherView.showToast();//调用View层的接口方法显示Toast
try {
Thread.sleep(4000);
String info="21° 阴";//模拟访问网络获取天气数据
mIWeatherModel.setInfo(info);//调用Model层的方法存储数据
String weather=mIWeatherModel.getInfo();//调用Model层的方法获取数据
mIWeatherView.setWeatherInfo(weather);//调用View层的方法设置数据到TextView。
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
mIWeatherView.dismissToast();//调用View层的接口方法显示Toast
}
}
}).start();
}
4:剩下的就是在接口的实现类中写具体操作的代码。
public class MainActivity extends AppCompatActivity implements IWeatherView{
private Button mButton;
private TextView mTextView;
private WeatherPresenter mWeatherPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton=findViewById(R.id.button);
mTextView=findViewById(R.id.textView);
mWeatherPresenter=new WeatherPresenter(this);//创建Presenter类对象,以便在V层调用Presenter的方法,这里构造方法传入this。
mButton.setOnClickListener(new View.OnClickListener() {//点击事件
@Override
public void onClick(View view) {
mWeatherPresenter.requestWeatherInfo();//调用Presenter里面的方法。
}
});
}
@Override
public void showToast() {//因为此方法在WeatherPresenter中是在子线程中调用的,所有要进行UI操作需回到UI线程。
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"正在加载···",Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void dismissToast() {//因为此方法在WeatherPresenter中是在子线程中调用的,所有要进行UI操作需回到UI线程。
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"加载完成",Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void setWeatherInfo(final String info) {//因为此方法在WeatherPresenter中是在子线程中调用的,所有要进行UI操作需回到UI线程。
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText(info);
}
});
}
}
public class WeatherModel implements IWeatherModel {
private String mString;
@Override
public void setInfo(String info) {//存储数据,模拟数据库操作。
mString=info;
}
@Override
public String getInfo() {//获取数据
return mString;
}
}
(以上是自己的理解,可参考这篇文章)