Android中MVP模式的了解及实例
Android中MVP的由来
在了解MVP之前我相信很多人已经学习过MVC这个框架了!MVP的诞生可以说是建立在MVC在安卓某些不足的方面
MVC简介
.M对应Model,代表业务数据
.V对应View,代表视图
.C对应Controller,代表控制器。
具体逻辑结构如下图所示:
来自百度百科MVC框架将视图和数据分离,在WEB领域有着十分广泛的应用。
用户通过界面组件进行操作,也就是View层,相应的动作会传递给控制器也就是Controller层,而Controller根据自己的业务逻辑去操作数据层也就是Model,
而最终数据层的变化会同步更新到视图层。
MVC的主要目的是为了视图和数据分离,这对于开发大型软件来说更方便进行模块的划分,提高编码速度与质量。
Android中的MVC
Android世界中也经常运用到MVC模式。
Activity对应视图界面也就是View层。
数据库文件,Sharedprefrence,内存缓冲,磁盘缓冲等数据内容对应Model层。
而Controller控制层基本上也由Activity层面来进行。
Android中mvc中基本动作流程
假设我们现在有这么一个需求,需要在一个界面上显示当天的天气,不仅如此,还可以通过列表项选择以往某一天的天气。
mvc架构开发的话,大概是这样。
在layout制定相应的布局文件,然后显示在Activity上,用于显示天气信息。这对应于View层,这里的View并不是Android中开发中的组件view而是对视图的统称.
Activity在onCreate方法或者onResume方法去服务器获取数据,或者通过界面上的某个按钮之类去启动获取服务器数据的任务,这里就对应到View—>Controller,只不过这里的View和Controller对是由Activity来完成。
Controller获取到了数据之后,分别存在,内存、磁盘和数据库中,并且数据获取成功或者失败后,Activity界面需要同步更新状态。这由对应上面流程中的Controller—>Model 和Model—->View。
(这是你或许会想:MVC这思路不是很清晰吗??为什么还要整一个MVP呢?因为Android的特殊性,
使得Activity对应了MVC中的V和C,同时担任两个角色,就不符合软件设计原则的“单一职责”原则。但现实中是很多的APP代码中有这么的处境,特别是Androi原生的很多系统APK,
某些Activity动则几千行代码。 况且,随着项目的深入发展,很多逻辑很越来越复杂,Activity处理的东西也会越来越多,代码越来越臃肿。这样一来维护起来的代价就会越来越高,
这是因为View的变化会引起Controller的很多变化,反之亦然。用一句大白话来说明就是–某一段代码的变动会引起很多其他相关联的代码的改动。
)
MVP是基于MVC的,它的架构图如下:
图片来自百度百科.M(Model) 数据相关层
.V(View) 视图层,如Activity上的布局
.P(Presenter) 纽带层,用来连接Model与View.
MVP开发在Android中的基本流程
1. View层定义View.interface,用来定义View的行为。一般由Activity或者是Fragment来实现这个接口,它定义了View视图的各种变化,如设置Textview,加载对话框,更新进度条等。
2. Model层定义Modle.interface,这个是用来定义数据层发生变化时的通知接口,因为Model不能直接与View交互,所以它与Presenter交互,然后再通过Presenter间接达到与View的交互。
3. Presenter翻译的意思是主持人,也就是主持场合,控制节奏的意思。在这时Presenter就负责具体的业务逻辑,请求数据,把数据送到Model,或者监听Model的数据变化,接受View
层的动作,负责通过通知View层的视图变化。
类似于王者荣耀中的打野位(掌控节奏)
MVP实践
先是我们需要些的代码有哪几项:
而我们需要实现的效果则是:
1 2 3例子本身是非常简单的,可以说用MVP简直是多此一举。
主要是说学习这个思想。
具体代码如下:
----------------------------------WetherPresenter-------------------------------
package com.example.acer.mvpdome.presenter;
import com.example.acer.mvpdome.model.IWetherImpl;
import com.example.acer.mvpdome.model.IWetherModel;
import com.example.acer.mvpdome.view.IWetherView;
public class WetherPresenter
{
IWetherModelmModel;
IWetherViewmView;
////因为Presenter持有View的引用,所以在这里要将View.interface注入到Presenter当中。
public WetherPresenter(IWetherView mView) {
this.mView = mView;
mModel =new IWetherImpl();
}
//供View层调用,用来请求天气数据
public void requestWetherInfo(){
getNetworkInfo();
}
private void getNetworkInfo()
{
new Thread(new Runnable() {
@Override
public void run()
{
try {
//打开等待对话框
showWaitingDialog();
//模拟网络耗时
Thread.sleep(6000);
String info ="21度,晴转多云";
//保存到Model层
saveInfo(info);
//从Model层获取数据,为了演示效果,实际开发中根据情况需要。
String localinfo = localInfo();
//通知View层改变视图
updateWetherInfo(localinfo);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
//取消对话框
dissmissWaitingDialog();
}
}).start();
}
private void showWaitingDialog(){
if (mView !=null) {
mView.showWaitingDialog();
}
}
private void dissmissWaitingDialog(){
if (mView !=null) {
mView.dissmissWaitingDialog();
}
}
private void updateWetherInfo(String info){
if (mView !=null) {
mView.onInfoUpdate(info);
}
}
private String localInfo(){
return mModel.getInfo();
}
private void saveInfo(String info){
mModel.setInfo(info);
}
}
---------------------------------IWetherView---------------------------
package com.example.acer.mvpdome.view;
public interface IWetherView
{
/**1.显示天气信息
*2.显示获取信息等待对话框
* 3.取消显示对话框
*/
public void showWaitingDialog();
public void dissmissWaitingDialog();
public void onInfoUpdate(String info);
}
---------------------------MainActivity------------------------------
package com.example.acer.mvpdome.view;
import android.app.ProgressDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.example.acer.mvpdome.R;
import com.example.acer.mvpdome.presenter.WetherPresenter;
public class MainActivityextends AppCompatActivityimplements IWetherView
{
WetherPresentermPresenter;
private TextViewmTvInfo;
private Buttonmbtn;
private ProgressDialogmDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPresenter =new WetherPresenter(this);
mbtn=findViewById(R.id.mbtn);
mTvInfo=findViewById(R.id.mTvInfo);
mbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mPresenter.requestWetherInfo();
}
});
}
@Override
public void showWaitingDialog()
{
runOnUiThread(new Runnable() {
@Override
public void run()
{
if (mDialog !=null &&mDialog.isShowing())
{
mDialog.dismiss();
}
mDialog = ProgressDialog.show(MainActivity.this,"","正在获取中...");
}
});
}
@Override
public void dissmissWaitingDialog() {
runOnUiThread(new Runnable() {
@Override
public void run()
{
if (mDialog !=null &&mDialog.isShowing())
{
mDialog.dismiss();
}
}
});
}
@Override
public void onInfoUpdate(final String info)
{
Log.d("-------------","onInfoUpdate: "+info);
runOnUiThread(new Runnable() {
@Override
public void run()
{
mTvInfo.setText(info);
}
});
}
}
---------------------------------------IWetherModel-------------------------------------------
package com.example.acer.mvpdome.model;
public interface IWetherModel
{
//提供数据
public String getInfo();
//存储数据
public void setInfo(String info);
}
----------------------------------------------IWetherImpl--------------------------------------
package com.example.acer.mvpdome.model;
public class IWetherImplimplements IWetherModel
{
private Stringinfo;
@Override
public String getInfo()
{
return info;
}
@Override
public void setInfo(String info)
{
this.info=info;
}
}
分析:
这里可以看成三个人:主持人甲,拿着数据的人乙,负责展示的人丙。
首先是拿着数据的人乙,和model区别不大,接口,实现类!一路过基本上多可以理解
然后是负责展示的人丙,展示的方式的实现,接口,问题也不大!
最后主持人甲要做的事情就多了,因为要同时对View和Model对接,所以内部必须持有它们的接口引用
而Presenter也要开发API供View调用。
所以Presenter要有requestWetherInfo()方法,剩下的基本都是它对其他两个的方法的调用!!
有兴趣的朋友可以继续深入研究