一:概念
MVC模式中Activity对应了MVC中的V和C,同时担任两个角色,会导致Activity过于复杂臃肿,因为MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。还有一点就是Presenter与View之间,Presenter与Model之间的交互是通过接口的方式来进行的。简而言之即Model层与View层不直接交互,而是通过Presenter来处理。Model层声明接口、View层声明接口提供给Presenter调用来间接实现M层与V层的交互,Presenter也提供一些方法供View、Model层调用。
MVP:
Model:模型层,处理数据之类,如数据库操作,访问网络等。
View:视图层,xml布局文件及Activity、fragment。
Presenter:Presenter表示器(也称主持人),通过调用V、M层的接口来连接Model与View.
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; } }(以上是自己的理解,可参考 这篇文章)