今天来看看Android的MVP模式,使用框架开发,开发速度以及代码的目录结构会别有一番风格。

Google的demo:https://github.com/googlesamples/android-architecture

目前已经完成的示例有
todo-mvp(mvp基础架构示例)

todo-mvp-loaders(基于mvp基础架构项目,获取数据部分使用了Loaders架构)

todo-mvp-databinding(基于mvp基础架构项目,使用了数据绑定组件)

todo-mvp-clean(基于mvp基础架构项目,使用了clean架构的概念)

todo-mvp-dagger(基于mvp基础架构项目,使用了dagger2进行依赖注入)

一张网上的图了解MVP:

这种分层的好处:层与层之间的耦合性低,模块的复用性高,可维护性更好,每层可以单独存在,这样可测性更好

model为上层提供数据,model处理上层传递的数据

presenter是处于mvp的中间层,在view和model中起一个承上启下的作用。presenter会把view交给自己的命令进行一定的校验等操作交给model处理,会把model处理的结果交给view,presenter会根据获取的数据成功与否来通知view应该是显示成功界面还是失败界面。

view就是用户直接看到的界面,一个view可以同时拥有多个presenter,也可以只有一个presenter。
Android中的Activity,Fragment在mvp中是作为view来使用的,各种Adapter是放在view层的。

以下就以登陆界面看看怎么使用MVP结构,先看看一般的(新手)登陆写法

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;public class LoginActivity extends Activity {private EditText  mUserName, mPassword;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_login);initView();}private void initView() {// findViewById.....}/*** 登陆按钮,需要验证输入的数据合法性* @param view*/public void loginCheck(View view){String userName = mUserName.getText().toString();String password = mPassword.getText().toString();//验证用户输入的密码是否合法if(!validate(userName) || !validate(password)){//告诉用户输入的用户名或密码不合法}  else{//开始登陆login(userName,password);}}/*** 访问网络进行登陆,分登陆成功和失败,显示不同的界面* @param userName* @param password*/private void login(String userName, String password) {}/*** 验证数据的合法性 非空等等* @param userName* @return*/private boolean validate(String userName) {// TODO Auto-generated method stubreturn false;}}

这种写法不是不可以,而是所有的功能都写在了一起,耦合性太高,然后可能还会狡辩,你看我所有功能都分方法了,方法分的多清楚...不说了,看看使用MVP来代码重构

从model层开始 ,LoginModel 使用 enum 做一个单例

import java.io.UnsupportedEncodingException;import org.apache.http.entity.StringEntity;import android.util.Log;import com.example.login_mvp.model.interfaces.HttpListener;
import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.RequestParams;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.http.client.HttpRequest.HttpMethod;/*** 联网获取数据,使用xUtil工具* enum  实现单例* @author chenling0418**/
public enum LoginModel {/** enum 实现单例* 定义一个枚举的元素,它就代表了LoginModel的一个实例。*/INSTANCE;/** 登陆* @param name 姓名* @param password 密码* @param loginListener 登陆结果的回调*/public void login(String name,String password,final HttpListener loginListener){// 使用xUtil ,HttpUtils也应该只有一个实例,这里是模拟HttpUtils httpUtils = new HttpUtils();RequestParams requestParams = new RequestParams();// 建议使用 JSON交互   JsonObjecttry {requestParams.setBodyEntity(new StringEntity("your params"));} catch (UnsupportedEncodingException e) {e.printStackTrace();Log.i("slack", "error:"+e.toString());}// send(HttpMethod method, String url, RequestParams params, RequestCallBack<Object> callBack)httpUtils.send(HttpMethod.POST, "your webservice host", requestParams, new RequestCallBack<String>() {@Overridepublic void onFailure(HttpException arg0, String error) {// TODO Auto-generated method stubif(loginListener != null){loginListener.onFailure(error);}}@Overridepublic void onSuccess(ResponseInfo<String> result) {// TODO Auto-generated method stubif(loginListener != null){loginListener.onSuccess(result.result);}}});}}

接着是 Presenter ,LoginPresenter

import com.example.login_mvp.model.LoginModel;
import com.example.login_mvp.model.bean.UserInfo;
import com.example.login_mvp.model.interfaces.HttpListener;
import com.example.login_mvp.presenter.interfaces.ILoginPresenter;
import com.example.login_mvp.view.interfaces.ILoginView;/*** 登录的 具体的presenter,负责协调 view 和 model * presenter 会有多个,负责不同功能* @author chenling0418**/
public class LoginPresenter implements ILoginPresenter{private ILoginView mLoginView;@Overridepublic void init(ILoginView view) {mLoginView = view;mLoginView.initView();//初始化view(findById...),此处其实是回调}@Overridepublic void login(String name, String password) {//验证name,password的合法性,if(validate(name) && validate(password)){// 获取单例LoginModel.INSTANCE.login(name, password, new HttpListener() {@Overridepublic void onSuccess(String result) {// 这里假设成功后返回的是用户的信息(json) 需要对result处理然后传入 onShowSuccessLoginViewUserInfo userInfo = new UserInfo();//下面的代码在ui线程中执行,这就不写具体的实现了mLoginView.onShowSuccessLoginView(userInfo);mLoginView.dissLoginingView();}@Overridepublic void onFailure(String error) {//下面的代码在ui线程中执行,这就不写具体的实现了mLoginView.onShowFailedLoginView();mLoginView.dissLoginingView();}});}else{//假设1代表账号,密码不合法mLoginView.onShowLoginCheckErrorView();}}/*** 验证数据的合法性 非空等等* @param userName* @return*/private boolean validate(String userName) {// TODO Auto-generated method stubreturn false;}@Overridepublic void onStop() {// TODO Auto-generated method stub}@Overridepublic void onResume() {// TODO Auto-generated method stub}@Overridepublic void onDestroy() {// TODO Auto-generated method stub}@Overridepublic void onPause() {// TODO Auto-generated method stub}@Overridepublic void onStart() {// TODO Auto-generated method stub}}

View 层,这里做一个基类BaseActivity

import java.util.HashSet;
import java.util.Set;import com.example.login_mvp.presenter.interfaces.IPresenter;import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;/*** BaseActivity 所有Activity的基类* * @author chenling0418* */
public abstract class BaseActivity extends FragmentActivity {private Set<IPresenter> mAllPresenters = new HashSet<IPresenter>();/*** * 获取layout的id,具体由子类实现* * @return*/protected abstract int getLayoutResId();/*** 需要子类来实现,获取子类的IPresenter,一个activity有可能有多个IPresenter*/protected abstract IPresenter[] getPresenters();// 初始化presenters,protected abstract void onInitPresenters();/*** * 从intent中解析数据,具体子类来实现* * @param argIntent*/protected void parseArgumentsFromIntent(Intent argIntent) {}/*** 此处是把所有的presenter 添加到  mAllPresenters 集合* * 这里用到了设计模式里的 观察者模式,对象之间的一对多的依赖,这样一来,当一个对象改变时,* 它的所有的依赖者都会收到通知并自动更新* */private void addPresenters() {IPresenter[] presenters = getPresenters();if (presenters != null) {for (int i = 0; i < presenters.length; i++) {mAllPresenters.add(presenters[i]);}}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(getLayoutResId());if (getIntent() != null) {parseArgumentsFromIntent(getIntent());}addPresenters();onInitPresenters();}@Overrideprotected void onResume() {super.onResume();// 依次调用IPresenter的onResume方法for (IPresenter presenter : mAllPresenters) {if (presenter != null) {presenter.onResume();}}}@Overrideprotected void onDestroy() {super.onDestroy();// 依次调用IPresenter的onResume方法for (IPresenter presenter : mAllPresenters) {if (presenter != null) {presenter.onDestroy();}}}// ...其他生命周期方法也是类似,调用IPresenter中相应的生命周期方法...}

具体的实现的类

import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;import com.example.login_mvp.R;
import com.example.login_mvp.model.bean.UserInfo;
import com.example.login_mvp.presenter.LoginPresenter;
import com.example.login_mvp.presenter.interfaces.IPresenter;
import com.example.login_mvp.view.interfaces.ILoginView;/*** view 只专心负责各种 显示* * @author chenling0418**/
public class LoginActivity extends BaseActivity implements ILoginView{private LoginPresenter mLoginPresenter = new LoginPresenter();private EditText  mUserName, mPassword;private Button mLogin;@Overridepublic void initView() {//  ...初始化view的代码... findViewById...mLogin = (Button)findViewById(R.id.login);mLogin.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubmLoginPresenter.login(mUserName.getText().toString(), mPassword.getText().toString());}});}@Overridepublic void onShowSuccessLoginView(UserInfo userInfo) {// ....显示登录成功界面....}@Overridepublic void onShowFailedLoginView() {// ...显示登录失败界面...}@Overridepublic void showLoginingView() {// ...显示登录进度条对话框...}@Overridepublic void dissLoginingView() {//  ...消失登录进度条对话框...}@Overrideprotected int getLayoutResId() {return R.layout.activity_login;}@Overrideprotected IPresenter[] getPresenters() {return new IPresenter[]{ mLoginPresenter};}@Overrideprotected void onInitPresenters() {mLoginPresenter.init(this);}@Overridepublic void onShowLoginCheckErrorView() {//  ...显示填入信息错误界面...}}

我只能表示看懂了,代码里有注释

参考:http://android.jobbole.com/83294/#rd(特别感谢作者的无私奉献)

GitHub: https://github.com/CL-window/mvpTest/

Android之MVP模式相关推荐

  1. android 适合mvp模式,Android中的MVP:如何使Presenter层系统化?

    MVP(Model View Presenter)模式是著名的 MVC(Model View Controller)的衍生物,并且是 Android 应用程序中管理表示层的***的模式之一. 这篇文章 ...

  2. Android之MVP 模式:简单易懂的介绍方式

    转载:https://segmentfault.com/a/1190000003927200 Android MVP Pattern Android MVP 模式1 也不是什么新鲜的东西了,我在自己的 ...

  3. ym——Android开发MVP模式(解决了View和Model的耦合)

    转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! 什么是MVP呢?它又和我们常常听到的MVC有什么关系了以及区别呢? MVP 是从经典的 ...

  4. Android开发MVP模式(解决了View和Model的耦合)

    转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! 什么是MVP呢?它又和我们常常听到的MVC有什么关系了以及区别呢? MVP 是从经典的 ...

  5. android 的MVP模式的介绍

    当下开发中使用最多的最普遍的有三种模式就是MVC,MVP和MVVM.相信大家对这三个名词并不陌生,他们在我们的开发用应用的及其广泛,今天我就浅谈一下我了解的MVP设计模式.说MVP之前不得不谈谈MVC ...

  6. Android开发MVP模式--项目实战

    1 前言 苏宁+App是苏宁易购集团零售云研发中心分销研发中心主要产品之一,由于项目处于初期阶段,业务逻辑复杂,导致业务需求变动快,常常在开发甚至测试过程中出现界面或者后台接口调整的情况. App客户 ...

  7. 浅谈Android中MVP模式用于实际项目中的问题与优化

    学习MVP不算久,前段时间才把公司的两个项目完全转换为MVP模式,改了下来,略有心得,给大家分享一下. 才开始学习使用MVP时,看到大家说了很多MVP的优点,代码复用,条理清晰等等.不过我改下来发现, ...

  8. android MVP连接服务器,Android之MVP模式实现登陆和网络数据加载

    MVP简介 相信你们对 MVC 都是比较熟悉了:M-Model-模型.V-View-视图.C-Controller-控制器,MVP做为MVC的演化版本,也是做为用户界面(用户层)的实现模式,那么相似的 ...

  9. Flutter Candies 一桶天下,一个小例子彻底搞懂Android的MVP模式到底是什么

    | | | | | ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2lt ...

最新文章

  1. 计算机队列概念,2020计算机专业考研数据结构知识点:栈、队列和数组
  2. nslang oracle_解决ojdbc14连接oracle报“java.sql.SQLException: Io 异常: Size Data Unit (SDU) mismatch”异常问题...
  3. 在PowerPoint 2010中将鼠标用作激光笔
  4. NG Ng-container(逻辑容器)
  5. linux终端字体安装,在Gnome-terminal下安装以及使用Monaco字体
  6. MyBatis Plus 联合查询
  7. 学习日志-《微习惯》笔记
  8. 苹果2017秋季大会回顾
  9. 毕业论文开题报告撰写指南-宾夕法尼亚州立大学研究生写作中心
  10. 高并发中 QPS、TPS、RT、Load、PV、UV都是什么意思!
  11. openstack的部署与云主机实例
  12. 创建Hive外部表,关联HDFS文件
  13. 4路 HX5+Emulex 8Gb 实现 BOFM 实施 -chenjhh@dc
  14. OpenGLES2.0后台绘制图片
  15. Hadoop百度百科
  16. 七牛云配置token-----CryptoJS.js
  17. iPhone4S价格走势平稳 现价5999值得买
  18. CELL_FACH和CELL_PCH状态
  19. linux下comsol安装教程6,新手求问,linux集群下无图形界面安装comsol报错
  20. 第三方登录——QQ、微信、新浪微博和百度登录

热门文章

  1. OPC DA调研报告
  2. 大功率的用电电器为什么要用三孔插座?
  3. Python绘制指数加权平均线
  4. 计算机五笔字型编码方法,《五笔字型输入的编码规则》说课稿
  5. 点击“加入QQ群”链接打开电脑QQ扫码后发现登录地点不是本地
  6. 27.WLAN组网介绍_VLAN在WLAN业务中的应用
  7. Qt 错误提示1: invalid use of incomplete type ‘***‘
  8. finalize的作用
  9. final、finalize 和 finally
  10. 【2020年保研记】浙大软院+中科院信工所+北师大人工智能学院+华中科技网安学院+四川大学网安学院+中山大学系统科学与工程学院