presenter 主持人。主导器

======

1. 明确需求,界面如下:可存,可根据id读取数据。

包结构图

2. 建立bean
  1. public class UserBean {
  2. private String mFirstName;
  3. private String mLastName;
  4. public UserBean(String firstName, String lastName) {
  5. this. mFirstName = firstName;
  6. this. mLastName = lastName;
  7. }
  8. public String getFirstName() {
  9. return mFirstName;
  10. }
  11. public String getLastName() {
  12. return mLastName;
  13. }
  14. }
3. 建立model(处理业务逻辑,这里指数据读写),先写接口,后写实现
  1. public interface IUserModel {
  2. void setID(int id);
  3. void setFirstName(String firstName);
  4. void setLastName(String lastName);
  5. int getID();
  6. UserBean load(int id);// 通过id读取user信息,返回一个UserBean
  7. }
实现不在这里写了。
4. 建立view(更新ui中的view状态),这里列出需要操作当前view的方法,也是接口
  1. public interface IUserView {
  2. int getID();
  3. String getFristName();
  4. String getLastName();
  5. void setFirstName(String firstName);
  6. void setLastName(String lastName);
  7. }
5. 建立presenter(主导器,通过iView和iModel接口操作model和view),activity可以把所有逻辑给presenter处理,这样java逻辑就从手机的activity中分离出来。
  1. public class UserPresenter {
  2. private IUserView mUserView;
  3. private IUserModel mUserModel;
  4. public UserPresenter(IUserView view) {
  5. mUserView = view;
  6. mUserModel = new UserModel();
  7. }
  8. public void saveUser( int id, String firstName, String lastName) {
  9. mUserModel.setID(id);
  10. mUserModel.setFirstName(firstName);
  11. mUserModel.setLastName(lastName);
  12. }
  13. public void loadUser( int id) {
  14. UserBean user = mUserModel.load(id);
  15. mUserView.setFirstName(user.getFirstName()); // 通过调用IUserView的方法来更新显示
  16. mUserView.setLastName(user.getLastName());
  17. }
  18. }
6. activity中实现iview接口,在其中操作view,实例化一个presenter变量。
  1. public class MainActivity extends Activity implements OnClickListener,IUserView {
  2. UserPresenter presenter;
  3. EditText id,first,last;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout. activity_main);
  8. findViewById(R.id. save).setOnClickListener( this);
  9. findViewById(R.id. load).setOnClickListener( this);
  10. id = (EditText) findViewById(R.id. id);
  11. first = (EditText) findViewById(R.id. first);
  12. last = (EditText) findViewById(R.id. last);
  13. presenter = new UserPresenter( this);
  14. }
  15. @Override
  16. public void onClick(View v) {
  17. switch (v.getId()) {
  18. case R.id. save:
  19. presenter.saveUser(getID(), getFristName(), getLastName());
  20. break;
  21. case R.id. load:
  22. presenter.loadUser(getID());
  23. break;
  24. default:
  25. break;
  26. }
  27. }
  28. @Override
  29. public int getID() {
  30. return new Integer( id.getText().toString());
  31. }
  32. @Override
  33. public String getFristName() {
  34. return first.getText().toString();
  35. }
  36. @Override
  37. public String getLastName() {
  38. return last.getText().toString();
  39. }
  40. @Override
  41. public void setFirstName(String firstName) {
  42. first.setText(firstName);
  43. }
  44. @Override
  45. public void setLastName(String lastName) {
  46. last.setText(lastName);
  47. }
  48. }
7. 所谓的mvp,即是(model-处理业务逻辑(主要是数据读写,或者与后台通信(其实也是读写数据)),view-处理ui控件,presenter-主导器,操作model和view)
------------
1. 需求,这个是《android开发必知的50个诀窍》一书中的mvp章节的需求。

在splash页面中,判断是否有网络连接,有则跳到下个页面,无则弹出一条消息通知用户,同时在检查网络是否正常的期间显示一个进度条。
 

2. 类目录结构

  1. 3. model接口和实现
  2. public interface INetConnect {
  3. boolean isNetConnect( Context context);
  4. }
  5. public class NetConnect implements INetConnect {
  6. @Override
  7. public boolean isNetConnect(Context context) {
  8. if (context != null) {
  9. ConnectivityManager mConnectivityManager = (ConnectivityManager) context
  10. .getSystemService(Context. CONNECTIVITY_SERVICE);
  11. NetworkInfo mNetworkInfo = mConnectivityManager
  12. .getActiveNetworkInfo();
  13. if (mNetworkInfo != null) {
  14. return mNetworkInfo.isAvailable();
  15. }
  16. }
  17. return false;
  18. }
  19. }
  20. 4. view接口
  21. public interface ISplashView {
  22. void showProcessBar();
  23. void hideProcessBar();
  24. void showNetError();
  25. void startNextActivity();
  26. }
  27. 5. presenter实现
  28. public class SplashPresenter {
  29. private INetConnect connect;
  30. private ISplashView iView;
  31. public SplashPresenter(ISplashView iView){
  32. this. iView = iView;
  33. connect = new NetConnect();
  34. }
  35. public void didFinishLoading(Context context){
  36. iView.showProcessBar();
  37. if( connect.isNetConnect(context)){
  38. iView.startNextActivity();
  39. } else{
  40. iView.showNetError();
  41. }
  42. iView.hideProcessBar();
  43. }
  44. }
  45. 6.activity中代码
  46. public class MainActivity extends Activity implements ISplashView{
  47. SplashPresenter presenter;
  48. private ProgressDialog progressBar;
  49. @Override
  50. protected void onCreate(Bundle savedInstanceState) {
  51. super.onCreate(savedInstanceState);
  52. setContentView(R.layout. activity_main);
  53. presenter = new SplashPresenter( this);
  54. }
  55. @Override
  56. protected void onResume() {
  57. super.onResume();
  58. presenter.didFinishLoading( this);
  59. }
  60. @Override
  61. public void showProcessBar() {
  62. if ( progressBar == null) {
  63. progressBar = new ProgressDialog( this);
  64. progressBar.setCancelable( true);
  65. progressBar.setCanceledOnTouchOutside( true);
  66. progressBar.setMessage( "更新数据中,请稍后" );
  67. }
  68. progressBar.show();
  69. }
  70. @Override
  71. public void hideProcessBar() {
  72. progressBar.hide();
  73. }
  74. @Override
  75. public void showNetError() {
  76. Toast. makeText(this, "暂无网络", Toast.LENGTH_SHORT).show();
  77. }
  78. @Override
  79. public void startNextActivity() {
  80. Toast. makeText(this, "跳到下个activity", Toast.LENGTH_SHORT).show();
  81. }

==========

MVP模式简单实例

一个简单的登录界面(实在想不到别的了╮( ̄▽ ̄")╭),点击LOGIN则进行账号密码验证,点击CLEAR则重置输入。

项目结构看起来像是这个样子的,MVP的分层还是很清晰的。我的习惯是先按模块分Package,在模块下面再去创建model、view、presenter的子Package,当然也可以用model、view、presenter作为顶级的Package,然后把所有的模块的model、view、presenter类都到这三个顶级Package中,就好像有人喜欢把项目里所有的Activity、Fragment、Adapter都放在一起一样。

首先来看看LoginActivity

public class LoginActivity extends ActionBarActivity implements ILoginView, View.OnClickListener {

    private EditText editUser;
private EditText editPass;
private Button btnLogin;
private Button btnClear;
ILoginPresenter loginPresenter;
private ProgressBar progressBar; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //find view
editUser = (EditText) this.findViewById(R.id.et_login_username);
editPass = (EditText) this.findViewById(R.id.et_login_password);
btnLogin = (Button) this.findViewById(R.id.btn_login_login);
btnClear = (Button) this.findViewById(R.id.btn_login_clear);
progressBar = (ProgressBar) this.findViewById(R.id.progress_login); //set listener
btnLogin.setOnClickListener(this);
btnClear.setOnClickListener(this); //init
loginPresenter = new LoginPresenterCompl(this);
loginPresenter.setProgressBarVisiblity(View.INVISIBLE);
} @Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_login_clear:
loginPresenter.clear();
break;
case R.id.btn_login_login:
loginPresenter.setProgressBarVisiblity(View.VISIBLE);
btnLogin.setEnabled(false);
btnClear.setEnabled(false);
loginPresenter.doLogin(editUser.getText().toString(), editPass.getText().toString());
break;
}
} @Override
public void onClearText() {
editUser.setText("");
editPass.setText("");
} @Override
public void onLoginResult(Boolean result, int code) {
loginPresenter.setProgressBarVisiblity(View.INVISIBLE);
btnLogin.setEnabled(true);
btnClear.setEnabled(true);
if (result){
Toast.makeText(this,"Login Success",Toast.LENGTH_SHORT).show();
startActivity(new Intent(this, HomeActivity.class));
}
else
Toast.makeText(this,"Login Fail, code = " + code,Toast.LENGTH_SHORT).show();
} @Override
public void onSetProgressBarVisibility(int visibility) {
progressBar.setVisibility(visibility);
}
}

从代码可以看出LoginActivity只做了findView以及setListener的工作,而且包含了一个ILoginPresenter,所有业务逻辑都是通过调用ILoginPresenter的具体接口来完成。所以LoginActivity的代码看起来很舒爽,甚至有点愉♂悦呢 (/ω\*)。视力不错的你可能还看到了ILoginView接口的实现,如果不懂为什么要这样写的话,可以先往下看,这里只要记住LoginActivity实现了ILoginView接口

再来看看ILoginPresenter

public interface ILoginPresenter {
void clear();
void doLogin(String name, String passwd);
void setProgressBarVisiblity(int visiblity);
}
public class LoginPresenterCompl implements ILoginPresenter {
ILoginView iLoginView;
IUser user;
Handler handler; public LoginPresenterCompl(ILoginView iLoginView) {
this.iLoginView = iLoginView;
initUser();
handler = new Handler(Looper.getMainLooper());
} @Override
public void clear() {
iLoginView.onClearText();
} @Override
public void doLogin(String name, String passwd) {
Boolean isLoginSuccess = true;
final int code = user.checkUserValidity(name,passwd);
if (code!=0) isLoginSuccess = false;
final Boolean result = isLoginSuccess;
handler.postDelayed(new Runnable() {
@Override
public void run() {
iLoginView.onLoginResult(result, code);
}
}, 3000); } @Override
public void setProgressBarVisiblity(int visiblity){
iLoginView.onSetProgressBarVisibility(visiblity);
} private void initUser(){
user = new UserModel("mvp","mvp");
}
}

从代码可以看出,LoginPresenterCompl保留了ILoginView的引用,因此在LoginPresenterCompl里就可以直接进行UI操作了,而不用在Activity里完成。这里使用了ILoginView引用,而不是直接使用Activity,这样一来,如果在别的Activity里也需要用到相同的业务逻辑,就可以直接复用LoginPresenterCompl类了(一个Activity可以包含一个以上的Presenter,总之,需要什么业务就new什么样的Presenter,是不是很灵活(@ ̄︶ ̄@)),这也是MVP的核心思想

通过IVIew和IPresenter,把Activity的UI LogicBusiness Logic分离开来,Activity just does its basic job! 至于Model嘛,还是原来MVC里的Model。

再来看看ILoginView,至于ILoginView的实现类呢,翻到上面看看LoginActivity吧

public interface ILoginView {
public void onClearText();
public void onLoginResult(Boolean result, int code);
public void onSetProgressBarVisibility(int visibility);
}

代码这种东西放在日志里讲好像除了把整个版面拉长没什么卵用,我把几种自己常用的MVP的写法写成一个Demo项目,欢迎围观和PullRequest:Android-MVP-Pattern

==========

android中MVP模式(一) - 清风明月的专栏 - CSDN博客的更多相关文章

  1. mongodb丢失数据的原因剖析 - 迎风飘来的专栏 - CSDN博客 https://blog.csdn.net/yibing548/article/details/50844310

    mongodb丢失数据的原因剖析 - 迎风飘来的专栏 - CSDN博客 https://blog.csdn.net/yibing548/article/details/50844310

  2. Docker安装elasticsearch-head监控ES步骤 - gmijie的专栏 - CSDN博客

    原文:Docker安装elasticsearch-head监控ES步骤 - gmijie的专栏 - CSDN博客 Docker安装elasticsearch-head监控ES步骤 docker拉取镜像 ...

  3. 记一次压测问题定位:connection reset by peer,TCP三次握手后服务端发送RST_网络_c359719435的专栏-CSDN博客 https://blog.csdn.net/c359719435/article/details/80300433

    记一次压测问题定位:connection reset by peer,TCP三次握手后服务端发送RST_网络_c359719435的专栏-CSDN博客 https://blog.csdn.net/c3 ...

  4. 【转】Android Building System 总结 - 一醉千年 - CSDN博客

    原文网址:http://www.360doc.com/content/15/0314/23/1709014_455175716.shtml  Android Building System 总结 收藏 ...

  5. Android中MVP模式与MVC模式比較(含演示样例)

    原文链接 http://sparkyuan.me/ 转载请注明出处 MVP 介绍 MVP模式(Model-View-Presenter)是MVC模式的一个衍生. 主要目的是为了解耦,使项目易于维护. ...

  6. android中MVP模式

    http://blog.csdn.net/ysh06201418/article/details/46534799 Android App整体架构设计的思考   http://blog.csdn.ne ...

  7. 转----------数据库常见笔试面试题 - Hectorhua的专栏 - CSDN博客

    数据库基础(面试常见题) 一.数据库基础 1. 数据抽象:物理抽象.概念抽象.视图级抽象,内模式.模式.外模式 2. SQL语言包括数据定义.数据操纵(Data Manipulation),数据控制( ...

  8. python 使用函数名的字符串调用函数(4种方法)_black-heart的专栏-CSDN博客 https://blog.csdn.net/mrqingyu/article/details/84403924

    funcs = ['fetch_data_' + i for i in ( 'activities', 'banners', 'server_list')]# from operator import ...

  9. Android开发MVP模式解析

    http://www.cnblogs.com/bravestarrhu/archive/2012/05/02/2479461.html 在开发Android应用时,相信很多同学遇到和我一样的情况,虽然 ...

随机推荐

  1. python 删除2天前后缀为.log的文件

    python脚本 删除2天前后缀为.log的文件 #!/usr/local/python/bin/python #-*-coding=utf8 -*- import time import os,sy ...

  2. 初学Python-搞了一个linux用户登录监测小工具

    这几天突发奇想,想学习一下Python.看了点基础,觉得有点枯燥,所以想搞点什么.想了想,就随便弄个检测Linux用户登录的小工具吧~ 首先,明确一下功能: 1.能够捕获 linux 用户登录的信息. ...

  3. 那些年的 网络通信之 TCP/IP 传输控制协议 ip 加 端口 客户端上传文件到服务器端服务器端返回上传成功消息

    多线程开启, 客户端通过 Socket 流 上传文件到服务端的一个小程序练习. 1. 抓住阻塞式方法,去调试 2. 获取对应流对象操作对应的对象 这时候自己不能懵,一定要清晰,最好命名就能区别,一搞混 ...

  4. Javascript加速运动与减速运动

    加速运动,即一个物体运动时速度越来越快:减速运动,即一个物体运动时速度越来越慢.现在用Javascript来模拟这两个效果,原理就是用setInterval或setTimeout动态改变一个元素与另外 ...

  5. Flex 经验笔记一

    Module页面嵌套子Module页面直接用标签嵌入是不行的,无法显示出来,需要用到 ModuleManager 使用ModuleInfo 的 addEventListener 判断当子Module ...

  6. CSS3 - chrome,傲游,360极速浏览器不支持小于12px的字号的解决办法

    google流量器chrome,傲游,360极速浏览器都是基于webkit内核浏览器,默认不支持小于font-size小于12px 的字号,即定义font-size小于12px时会发现字体大小依然是1 ...

  7. iOS 6 & iOS 7 的适配笔记

    iOS 6 & iOS 7 的适配 场景1: 没有NavigationController,同时根视图是UIView- (void)viewWillLayoutSubviews{ if ([[ ...

  8. RHEL7 -- 使用Chrony设置时间与时钟服务器同步

    Chrony是一个开源的自由软件,它能保持系统时钟与时钟服务器(NTP)同步,让时间保持精确. 它由两个程序组成:chronyd和chronyc. chronyd是一个后台运行的守护进程,用于调整内核 ...

  9. 0行代码实现任意形状图片展示--android-anyshape

    前言 在Android开发中, 我们经常会遇到一些场景, 需要以一些特殊的形状显示图片, 比如圆角矩形.圆形等等.关于如何绘制这类形状, 网上已经有很多的方案,比如自定义控件重写onDraw方法, 通 ...

  10. Springbatch Miscellanea Notes

    1.scope="step",如下图,这是一种后绑定的方式,生成Step的时候,才去创建bean <bean id="testTasklet" paren ...