首页 > 系统 > Android > 正文

Android MVP 模式 理解与浅析

2019-11-07 23:39:06
字体:
来源:转载
供稿:网友

吾日三省吾身,为人谋而不忠乎?与朋友交而不信乎?传不习乎?

问题

上一个桌面项目MVC模式,在主activity中的代码超过了2000行,完成后感觉自己的项目很烂。虽然逻辑还算清晰,但是整个View层和Controller层感觉太臃肿了。

是时候该从MVC转到MVP模式了。下面就有我来简单的总结一点心得,介绍一下MVP模式,希望能给想用MVP的人一点帮助。

MVP总结和介绍

在MVP模式里通常包含4个要素:

(1)View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);

(2)View interface:需要View实现的接口,View通过View interface与PResenter进行交互,降低耦合,方便进行单元测试;

(3)Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);

(4)Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。

MVC与MVP模式比较

MVC模式

M : 业务层和模型层,相当与javabean和我们的业务请求代码 V : 视图层,对应Android的layout.xml布局文件

C : 控制层,对应于Activity中对于UI 的各种操作

MVP模式

M :还是业务层和模型层

V : 视图层的责任由Activity来担当P : 新成员Prensenter 用来代理 C(control) 控制层

MVPDemo讲解

下面我将用一个比较简单的Demo来向大家展示一下MVP,感受一下朵密的力量吧!

这里先来看一下biz,也就是业务层,业务层独立出去,该在哪儿调用就在哪儿调用。

RequestForDataBiz代码如下:

/** * Created by Administrator on 2017/2/25 0025. * 一个请求数据的biz * biz就是业务层的意思 */public interface RequestForDataBiz { //请求数据业务 void requestForData(OnRequestListener listener);}

数据请求的回掉接口,声明了成功和失败的方法 。OnRequestListener代码如下:

/** * Created by Administrator on 2017/2/25 0025. */ /*请求成功或者失败的回调接口,就和网络请求一样,一个网络请求的回调大致 有四个success,finish error cancel.这里就简单用两个,请求返回的数据为一个String集合*/public interface OnRequestListener { void onSuccess(List<String> data); void onFailed();}

RequestForDataBizIml代码如下:

请求的实现类为了模拟网络请求,开启了一个会sleep1秒的线程,然后装填请求的数据,通过OnRequestListener 接口回调出去,与我们平时开发的方式一致。

/** * Created by Administrator on 2017/2/25 0025. * 底下这是一个完整的网络请求,就是模拟网络数据太麻烦了,弄个假的简单说明 */public class RequestForDataBizIml implements RequestForDataBiz { @Override public void requestForData(final OnRequestListener listener) { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); ArrayList<String> data = new ArrayList<String>(); for (int i = 1; i < 12; i++) { data.add("item" + i); } if (null != listener) { listener.onSuccess(data); } } catch (Exception e) { e.printStackTrace(); } } }).start(); }// public static String doGet(Context context, String url, String params) //// throws IOException {// InputStream in = null;// URL realUrl = new URL(url.replace(" ", "%20"));// Log.e("infodoGet", "HttpUtil:doGet realUrl=" + realUrl.toString());// URLConnection conn = realUrl.openConnection();// conn.setConnectTimeout(5000);// conn.setReadTimeout(5000);// conn.setRequestProperty("accept", "*/*");// conn.setRequestProperty("connection", "Keep-Alive");// conn.setRequestProperty("user-agent",// "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)") ;// // conn.setRequestProperty("X-Bsl-Client" , Configure.PACKAGE_NAME + "^" + Configure.has_secure) ;//// try {// conn.connect();// in = conn.getInputStream();// BufferedReader br = new BufferedReader(new InputStreamReader(in));// String line = "";// result = new StringBuffer();// while (null != (line = br.readLine())) {// result.append(line);// }// } catch (SocketException e) {// return new String("SocketException");// } catch (SocketTimeoutException e) {// return new String("SocketException");// }//// try {// if (in != null) {// in.close();// }// } catch (IOException ex) {// ex.printStackTrace();// }// Log.e("infodoGet", "Httpresult.toString()"+ result.toString());// return result.toString();// }//}

业务层的业务在此处完成。

MVP的凝视与思考

由于Activity变成了view层不再去控制界面,但是具体的界面的改变api其实还是由Activity来提供的,所以在写MVP之前需要思考,View层需要哪些方法,要做哪些事情。

1,显示loading2,隐藏loading3,listview的初始化,展现页面4,弹出Toast消息

MVPView接口代码如下

/** * Created by Administrator on 2017/2/25 0025. * view层需要哪些方法,涉及到的UI展示。 */public interface MVPView { //显示loading progressBar void showLoading(); //隐藏loading progressBar void hideLoading(); //ListView的初始化,展示界面 void initListView(List<String> data); //Toast message void showMessage(String message);}

我们总结出View层需要的接口。我们的Activty就是View层,所以直接用Activity来实现上面的方法。将View视图层就完成。

public class MainActivity extends AppCompatActivity implements MVPView { private ProgressBar mMvpLoadingbarProgressBar; private ListView mMvpListviewListView; private RelativeLayout mActivityMainRelativeLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mMvpLoadingbarProgressBar = (ProgressBar) findViewById(R.id.mvp_loadingbar); mMvpListviewListView = (ListView) findViewById(R.id.mvp_listview); mActivityMainRelativeLayout = (RelativeLayout) findViewById(R.id.activity_main); } @Override public void showLoading() { mMvpLoadingbarProgressBar.setVisibility(View.VISIBLE); } @Override public void hideLoading() { mMvpLoadingbarProgressBar.setVisibility(View.GONE); } @Override public void initListView(List<String> data) { ArrayAdapter adapter = new ArrayAdapter(MainActivity.this,android.R.layout.simple_list_item_1,data); mMvpListviewListView.setAdapter(adapter); } @Override public void showMessage(String message) { Toast.makeText(this,message,Toast.LENGTH_SHORT).show(); }}

View视图层完成了。接下来开始写presenter层, 同样在写presenter之前想想控制层需要哪些方法?

(1)网络请求数据(2)点击事件的响应

MVPresenter代码如下

/** * Created by Administrator on 2017/2/25 0025. * - (1)网络请求数据 - (2)点击事件的响应 */public class MVPresenter { private MVPView mvpView; RequestForDataBiz requestBiz; private Handler mHandler; public MVPresenter(MVPView mvpView) { this.mvpView = mvpView; requestBiz = new RequestForDataBizIml(); mHandler = new Handler(Looper.getMainLooper()); } public void onResume(){ mvpView.showLoading(); requestBiz.requestForData(new OnRequestListener() { @Override public void onSuccess(final List<String> data) { //由于请求开启了新线程,所以用handler去更新界面 mHandler.post(new Runnable() { @Override public void run() { mvpView.hideLoading(); mvpView.initListView(data); } }); } @Override public void onFailed() { mvpView.showMessage("请求失败"); } }); } public void onItemClick(int position){ mvpView.showMessage("点击了item"+position); } public void onDestroy(){ mvpView = null; }}

Presenter完成(Presenter里面像不像接管了MVC模式中的C层?理解才是硬道理啊!),现在就剩下一件事,Activity中使用Presenter。

下面放大招:完整版的MainActivity:

/** MVP实现了,是不是很简洁?* 就是这么清爽,没有乱七八糟的业务。* 没有各种点击处理逻辑,Activity只需要提供View层的方法就可以了。* 你看现在activity的生命周期都托管给了MVPresenter。* 你要做的就是加深理解,把你的业务逻辑也带入到prenter层去处理。* */public class MainActivity extends AppCompatActivity implements MVPView ,AdapterView.OnItemClickListener{ private ProgressBar mMvpLoadingbarProgressBar; private ListView mMvpListviewListView; private RelativeLayout mActivityMainRelativeLayout; MVPresenter mMVPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mMvpLoadingbarProgressBar = (ProgressBar) findViewById(R.id.mvp_loadingbar); mMvpListviewListView = (ListView) findViewById(R.id.mvp_listview); mActivityMainRelativeLayout = (RelativeLayout) findViewById(R.id.activity_main); mMVPresenter=new MVPresenter(this); } @Override public void showLoading() { mMvpLoadingbarProgressBar.setVisibility(View.VISIBLE); } @Override public void hideLoading() { mMvpLoadingbarProgressBar.setVisibility(View.GONE); } @Override public void initListView(List<String> data) { ArrayAdapter adapter = new ArrayAdapter(MainActivity.this,android.R.layout.simple_list_item_1,data); mMvpListviewListView.setAdapter(adapter); } @Override public void showMessage(String message) { Toast.makeText(this,message,Toast.LENGTH_SHORT).show(); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { mMVPresenter.onItemClick(position); } //将生命周期托付给MVPresenter,你的逻辑,业务,在这里面做的事都可以转移到MVPresenter @Override protected void onResume() { super.onResume(); mMVPresenter.onResume(); } @Override protected void onDestroy() { mMVPresenter.onDestroy(); super.onDestroy(); }}

一点体会和小小的心得

可以看到,View只负责处理与用户进行交互,并把数据相关的逻辑操作都扔给了Presenter去做。视图层与控制层完全分离,可以让我们在界面还是很粗糙的情况下,先进行控制层的开发,甚至可以先让View层先提供方法出来,这样可以节省很多时间。

Github源码下载地址


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表