序言:夏天拉屎,一包手纸,九张擦汗,一张擦屎! 脏话只是用来辅助我发泄情绪的一种语言助词,跟我的素质半毛钱关系都没有!!!
一、MVC与MVP模式的简单介绍
先扯点皮外话,大神勿喷,本人才疏学浅,刚刚踏入博客之路,如有建议,欢迎提出,qq群号:659014357,更欢迎志同道合的小伙伴;
1.MVC即Model-View-Controller。M:逻辑模型,V:视图模型,C:控制器。
MVC模式下,系统框架的类库被划分为3种:模型(Model)、视图(View)、控制器(Controller)。模型对象负责建立数据结构和相应的行为操作处理。视图对象负责在屏幕上渲染出相应的图形信息展示给用户看。控制器对象负责截获用户的按键和屏幕触摸等事件,协调Model对象和View对象。
用户与视图交互,视图接收并反馈用户的动作;视图把用户的请求传给相应的控制器,由控制器决定调用哪个模型,然后由模型调用相应的业务逻辑对用户请求进行加工处理,如果需要返回数据,模型会把相应的数据返回给控制器,由控制器调用相应的视图,最终由视图格式化和渲染返回的数据,对于返回的数据完全可以增加用户体验效果展现给用户。
一个模型可以有多个视图,一个视图可以有多个控制器,一个控制器也可以有多个模型。
(1)、模型(Model)
Model是一个应用系统的核心部分,代表了该系统实际要实现的所有功能处理。比如:在视频播放器中,模型代表一个视频数据库及播放视频的程序函数代码;在拍照应用中,模型代表一个照片数据库,及看图片时的程序函数代码。在一个电话应用中,Model代表一个电话号码簿,以及拨打电话和发送短信的程序函数代码。
Model在values目录下通过xml文件格式生成,也可以通过硬编码的方式直接Java代码生成。View和Model是通过桥梁Adapter来连接起来。
(2)、视图(View)
View是软件应用传送给用户的一个反馈结果。它代表软件应用中的图形展示、声音播放、触觉反馈等职责。视图的根节点是应用程序的自身窗口。比如,视频播放器中可能包含当前播放的画面,这个画面就是一个视图。另一个视图组件可能是该视频的文字标题。再一个就是一些播放按键,比如:Stop、Start、Pause等按钮。
View在layout目录下通过xml文件格式生成,用findViewById()获取;也可以通过硬编码的方式直接Java代码生成。
(3)、控制器(Controller)
Controller在软件应用负责对外部事件的响应,包括:键盘敲击、屏幕触摸、电话呼入等。Controller实现了一个事件队列,每一个外部事件均在事件队列中被唯一标识。框架依次将事件从队列中移出并派发出去。
2、MVP即Model-View-Presenter。M:逻辑模型,V:视图模型,P:表示器。
MVP所对应的意义:M-Model-模型、V-View-视图、P-Presenter-表示器。 从MVC和MVP两者结合来看,Controlller/Presenter在MVC/MVP中都起着逻辑控制处理的角色,起着控制各业务流程的作用。而 MVP与MVC最不同的一点是M与V是不直接关联的也是就Model与View不存在直接关系,这两者之间间隔着的是Presenter层,其负责调控 View与Model之间的间接交互。
在 Android中很重要的一点就是对UI的操作基本上需要异步进行也就是在MainThread中才能操作UI,所以对View与Model的切断分离是 合理的。此外Presenter与View、Model的交互使用接口定义交互操作可以进一步达到松耦合也可以通过接口更加方便地进行单元测试。
(1)、模型(Model)
模型这一层之中做的工作是具体业务逻辑处理的实现,都伴随着程序中各种数据的处理,复杂一些的就需要实现一个Interface来降低耦合了。
(2)、视图(View)
V视图这一层体现的很轻薄,负责显示数据、提供友好界面跟用户交互就行。MVP下Activity和Fragment体现在了这一 层,Activity一般也就做加载UI视图、设置监听再交由Presenter处理的一些工作,所以也就需要持有相应Presenter的引用。例如,Activity上滚动列表时隐藏或者显示Acionbar(Toolbar),这样的UI逻辑时也应该在这一层。另外在View上输入的数据做一些 判断时,例如,EditText的输入数据,假如是简单的非空判断则可以作为View层的逻辑,而当需要对EditText的数据进行更复杂的比较时,如 从数据库获取本地数据进行判断时明显需要经过Model层才能返回了,所以这些细节需要自己把握。
(3)、表示器(Presenter)
Presenter这一层处理着程序各种逻辑的分发,收到View层UI上的反馈命令、定时命令、系统命令等指令后分发处理逻辑交由Model层做具体的业务操作。
看了这么多的概念是不是蒙圈了,没关系,下面才是文章的主要内容,让我来一步一步的带你理解MVP的写法,当你不断的模仿,总有一日你会恍然大悟,让我带你加快脚步。
二、MVP三步曲之一(低、中、高,对于有基础的可以直接看终极曲“封装版”)![]()
1、第一步 (调调很简单)![]()
首先,我们先对mvp模式进行剖析,第一步的特点就是把Model(其实它就是网络请求数据)层剥离出来,让我们更好的看清View层和Presenter层是如何交互的,接下来的案例我将用登录模块进行分析,也是为了小白的直接上手。
其次,我还要重申一点那就是mvp模式 是面向对象思想加面向接口编程,思想是自己的,接口编程我来(对就是放开那个姑娘,让我们来
)
![可怜](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cute.gif)
下面讲一下 注意了 从现在开始你们要好好看了
(1)项目结构的两种:
1.
每个页面分为一层,每一层中有Presenter,Activity(Fragment)即view的体现层,Interface(建立M、V、P的连接说白了就是接口回调),model
2
如果你的页面比较多的话
你可以采用上述图片分为四层
下面开始上代码:
最重要的部分 就是这接口桥梁 我先把桥梁给你搭上
![奋斗](http://static.blog.csdn.net/xheditor/xheditor_emot/default/struggle.gif)
package com.example.bandofbrotherszts.ztsmvpdemostep1.cantract; /** * Created by BandOfBrothersZTS on 2017/8/22. */ public interface LoginInterface { /** * 接口View “即Activity(Fragment)的所实现类“ */ interface View{ //setData方法是为了 Activity实现View接口之后 重写这个方法就可以直接拿到str 给TextView赋值 void setData(String str); }; /** * 接口Presenter 是LoginPresenter的所实现类 */ interface Presenter{ //我们所要做的就是 给一个TextView 赋值,所以Presenter 中需要有一个方法loadData() // 调用 model的网络请求 void loadData(); }; /** * 温馨提示 :你也可以吧interface Presenter{} 抽象接口换成 abstract class Presenter{} * 这样的话Presenter 是LoginPresenter的父类 LoginPresenter extends Presenter 即可 * 但是本着“单继承,多实现的原则” 我还是喜欢实现 因为你可能还有别的基类对不对 */ //TODO 不要问我mvp模式 m层在哪 不要忘了咱们第一步曲 是把m层剥离出去了 //TODO 但是这并不影响, 因为Model 是通过Presenter来调用的 看看mvc和mvp的对比图就明白了 //TODO 所以第一步曲的特点在于: 通过Presenter 来直接调用静态类 进行异步请求 }
接下来我们看一下 Presenter层(桥梁上的交警 指挥者,负责逻辑和业务工作)该怎么写:
package com.example.bandofbrotherszts.ztsmvpdemostep1.presenter; import com.example.bandofbrotherszts.ztsmvpdemostep1.cantract.LoginInterface; import com.example.bandofbrotherszts.ztsmvpdemostep1.model.LoginModel; /** *Created by BandOfBrothersZTS on 2017/8/22. */ public class LoginPresenter implements LoginInterface.Presenter{ /** *View 和 Presenter 是互通的 所以我要通过构造的方式拿到View * 拿到View Presenter就可以调用View中的方法了 * 嘿嘿,我又污了(拿到房卡 我就可以对里面姑娘为所欲为了!!!) */ private LoginInterface.View view; public LoginPresenter(LoginInterface.View view) { this.view = view; } @Override public void loadData() { String str = LoginModel.getData(); //得到数据 view.setData(str); //把得到的数据返回View层 供Activity用 } }
下面顺便看下咱们剥离出去的Modle:
package com.example.bandofbrotherszts.ztsmvpdemostep1.model; /** * Created by BandOfBrothersZTS on 2017/8/22. */ public class LoginModel { /** * 很简单就是网络强求数据,我比较懒所以我伪造一下数据 */ public static String getData(){ return "我是伪造的网络请求数据"; }; }
最后就是我们的Activity
看看它是如何工作的:
package com.example.bandofbrotherszts.ztsmvpdemostep1.activity; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.TextView; import com.example.bandofbrotherszts.ztsmvpdemostep1.R; import com.example.bandofbrotherszts.ztsmvpdemostep1.cantract.LoginInterface; import com.example.bandofbrotherszts.ztsmvpdemostep1.presenter.LoginPresenter; public class LoginActivity extends AppCompatActivity implements LoginInterface.View { private LoginInterface.Presenter mPresenter; private TextView dataTv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); initView(); /** * 注意了:::::::::::: * 向下转型 实例化LoginPresenter * 为什么这么写? 因为LoginInterface才是桥梁!!! */ mPresenter = new LoginPresenter(this); } private void initView() { dataTv = (TextView) findViewById(R.id.data_tv); dataTv.setOnClickListener(new View.OnClickListener() {//点击请求数据 @Override public void onClick(View v) { mPresenter.loadData(); } }); } @Override public void setData(String str) { dataTv.setText(str); } }
粘贴复制大军注意了 xml:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.bandofbrotherszts.ztsmvpdemostep1.activity.LoginActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" android:id="@+id/data_tv" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
三、总结:还记得调调吗?一起哼哼?
在剥离Model层后工作是这个样纸的:
(1)首先Activity 实现View 重写setData() , 通过桥梁方式实例化Presenter,拿到Presenter的操作权,实例化过程中给 Presenter传递过View的操作权 。
(2)Presenter 调用loadData(),之后通过view.setData() 达到传值目的。
现在你是不是对MVP中,比较复杂的View层和Presenter层的交互是不是理解了,如果不理解请仔细看一次,或者
加QQ群:659014357 !!! 需要你们的支持,你们是我继续写作的动力,感谢
。
如果你明白View和Presenter的交互了
,请看下一篇:点击打开链接