从零开始学MVP架构
来源:互联网 发布:python基础教程 在线 编辑:程序博客网 时间:2024/06/05 07:36
前言
首先如果你是一个半年以内的安卓初学者,如果你对逻辑思维的感受不够强烈的话,我不建议你立马接触MVP设计模式。为什么呢?因为我自己就是这波人里面的…尴尬个三秒钟,跳过。这种东西具体是什么呢?
身边其实有很多类似的例子,如果非要举个例子,我个人感觉跟盖房子有那么一丢丢类似,但又不完全类似。
以一个大型公司为例,它会分很多的部门,然后每个部门具有一定的职能,但其实很多公司的部门架构都是具有一定的相似性的,这也就是我们通常说的模式化~而每个人做的事情也许别人也能做,就好比Activity里面你也可以做联网操作,也可以做View操作,但是你啥事儿都让他一个做是不是有点累呢?所以,合理的结构与分工可以让整个综合体更有效率的运行与维护。
在此之前,我希望初学者不是抱着一口吃个胖子的心态去接触这种设计模式。由更浅到浅,会让你理解更明白。在学习MVP以前,我强烈建议先学习MVC【标准MVC不是那种不三不四的结构的Demo或者渣渣项目】,把这种分模块与分层的思想带到你的项目中。这里是我的MVC学习笔记:http://www.jianshu.com/p/894420ac8fdc
不懂的哥们姐们多写几遍,一定不要懒~
入门
首先对于网上的那些理论性的玩意儿,我不想复制粘贴过来。一个原因,太抽象不具体。我们很难理解那些看不到的玩意儿。
如果你学会了MVC,那你应该就会有一种体会,就是你的联网操作,数据操作,以及一些耗时的操作等都是写在Model中的,然后你把数据塞到要显示的View中的时候,都是在Activity或Fragment等等这些Java文件中的,那么这么做的好处是啥?没有好处我们肯定不会用它的对吧,我想很多人刚开始学习安卓的时候,写demo,例如写一个显示天气数据的Activity,肯定你View也写在里头,联网也写在里头,然后第一步怎么联网,第二步回调怎么写数据,第三部怎么显示消失动画等等…其实这也没啥,但是你啥都写在一个里面,你一个Activity要写两千多行咩?协同开发的时候是不是给别人一种坑的感觉咩?
同样是写个显示天气数据的demo,使用MVC,你的View相关的操作,全部是在Activity中的,而你的联网等全部是在Model中的,这样的话,我们就吧视图【你眼睛看到的,手摸到的】与联网【比较耗时间的需要异步的】,这两种行为用代码隔开了。对于单个文件来说,降低代码量,易于维护。对于模块式的开发形式来说,独立的东西往往比黏合在一起的东西好控制,也就是我们常说的解耦。
然后,在我学会MVC以后我再写MVP就很容易明白它的目的了。首先MVC我们已经清楚,M是做耗时操作与业务逻辑处理的,View是我们眼睛看到的,你就把它当作布局文件就好不要想太复杂。然后C就是controller,就是我们把布局文件连接起来的,那不就是我们的Activity嘛。然后,MVP则相当于进化版本的MVC。我们知道,如果你要把一行文字塞到TextView中,要使用的是setText的方法,这个方法是针对TextView这个View的操作,而你塞进去,这一动作,我们要把它独立出来看,比如我吃饭,我的吃,与饭进到嘴巴里面,综合来看是一个行为动作,但是这里呢就把它进一步独立开,吃是逻辑,而饭进到嘴巴里才是针对你的嘴巴的操作。
以上逻辑的解释如果你还看不懂,哥哥我就不好说啥了…
代码【demo参照:http://blog.csdn.net/knxw0001/article/details/39637273/ 进行了少量修改】
我们要实现一个这样的功能:可以从EditText读取用户信息并存取,也可以根据ID来从后台读出用户信息并显示在EditText中。
首先来看一下分包
看一下布局:
布局文件的相关代码我就不贴上来了比较简单
然后看上面那个分包的图,首先如果你会MVC,你就知道Model的作用是放置耗时的操作与业务逻辑的模块,在这个demo中,Model要做的事情是什么?主要做的工作是,把从View中拿到的数据存起来,以及从存入的地方读出来并且拿出来使用。
UserBean
public class UserBean { public UserBean(String first_name, String last_name) { this.first_name = first_name; this.last_name = last_name; } private String first_name; private String last_name; public String getFirst_name() { return first_name; } public void setFirst_name(String first_name) { this.first_name = first_name; } public String getLast_name() { return last_name; } public void setLast_name(String last_name) { this.last_name = last_name; }}
看一下UserModel接口以及它的实现类UserModelImp,如果你不知道为啥子要写个实现类,建议你先去把MVC学会并且使用熟练。
UserModel
相关备注:UserModel主要做的工作是,把从View中拿到的数据存起来,以及从存入的地方读出来给别的地方用public interface UserModel { void setId(int id); void setFirstName(String first_name); void setLastName(String last_name); UserBean getUserInfo(int id);//通过id获取first_name与last_name,返回一个UserBean}
UserModelImp
相关备注:实现UserModel接口,来把具体要做的工作放在这里public class UserModelImp implements UserModel { private int id; private String first_name; @Override public void setId(int id) { this.id = id; } @Override public void setFirstName(String first_name) { if (first_name != null && first_name.length() > 0) { this.first_name = first_name; } else { Toast.makeText(MainApplication.MainContext, "首次姓名不能为空", Toast.LENGTH_SHORT).show(); } } @Override public void setLastName(String last_name) { if (last_name != null && last_name.length() > 0) { MainApplication.userArray.append(id, new UserBean(first_name, last_name)); Toast.makeText(MainApplication.MainContext, "存入成功", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MainApplication.MainContext, "最后姓名不能为空", Toast.LENGTH_SHORT).show(); } } @Override public UserBean getUserInfo(int id) { return MainApplication.userArray.get(id); }}
那么在这个例子中的MVP的M部分已经完成,然后要看一下P,P是prensneter,意思是表现,展现出来,它很类似于controller,还以吃饭为例。如果controller表示吃饭这个整体动作,那么presenter就是拆分出来的吃,而View就是把饭送到嘴巴里的动作。
然后我们要先把饭送到嘴巴里才能吃对不对?看一下UserView接口。
UserView
相关备注:UserView可以做的工作是,从EditText塞入或读取数据,即与view的交互PS:对于View而言,它主要是面对View所做的操作,在本例中,对View的操作主要是从从EditText塞入或读取数据,然后与Button之间存在一定的交互public interface UserView { int getId(); String getFirstName(); String getLastName(); void setFirstName(String first_name); void setLastName(String last_name); void clearText();}
然后是吃的逻辑,也就是presenter
UserPresenter
相关备注:Presenter主要起到了一个连接器的作用,也就是承载了大量原来在Activity中的操作PS:以本例子的需求为例,主要要做两方面的操作,一方面是存,一方面是取,那么要在这里把View和Model的作用发挥出来public class UserPresenter { private UserView userView; private UserModel userModel; /*这里需要把View的实现类传入*/ public UserPresenter(UserView userView) { this.userView = userView; this.userModel = new UserModelImp();//这里是实现类 } /*存的操作*/ public void saveUserInfo(int id, String first_name, String last_name) { if (id != 0) { userModel.setId(id); userModel.setFirstName(first_name); userModel.setLastName(last_name); } else { Toast.makeText(MainApplication.MainContext, "id不能为0或为空", Toast.LENGTH_SHORT).show(); } userView.clearText(); } /*取的操作*/ public void readUserInfo(int id) { try { if (id != 0) { userView.setFirstName(userModel.getUserInfo(id).getFirst_name()); userView.setLastName(userModel.getUserInfo(id).getLast_name()); } else { throw new Exception(); } } catch (Exception e) { e.printStackTrace(); Toast.makeText(MainApplication.MainContext, "未查询到此数据", Toast.LENGTH_SHORT).show(); } }}
以上关于view和presenter的部署已经完成,接下来就要在Activity中来使用了。
MainActivity
public class MainActivity extends AppCompatActivity implements UserView, View.OnClickListener { private EditText etUserID; private EditText etUserFirstName; private EditText etUserLastName; private Button btnSave; private Button btnRead; private UserPresenter userPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); initView(); userPresenter = new UserPresenter(this); } private void initView() { etUserID = (EditText) findViewById(R.id.etUserID); etUserFirstName = (EditText) findViewById(R.id.etUserFirstName); etUserLastName = (EditText) findViewById(R.id.etUserLastName); btnSave = (Button) findViewById(R.id.btnSave); btnRead = (Button) findViewById(R.id.btnRead); btnSave.setOnClickListener(this); btnRead.setOnClickListener(this); } @Override//此方法里没有完全隔离【后期修改】 public int getId() { if (etUserID.getText().toString().length() > 0) { return Integer.parseInt(etUserID.getText().toString()); } else { return 0; } } @Override public String getFirstName() { return etUserFirstName.getText().toString(); } @Override public String getLastName() { return etUserLastName.getText().toString(); } @Override public void setFirstName(String first_name) { etUserFirstName.setText(first_name); } @Override public void setLastName(String last_name) { etUserLastName.setText(last_name); } @Override public void clearText() { etUserID.setText(""); etUserFirstName.setText(""); etUserLastName.setText(""); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btnSave: userPresenter.saveUserInfo(getId(), getFirstName(), getLastName()); break; case R.id.btnRead: userPresenter.readUserInfo(getId()); break; } }}
程序入口:MainApplication
public class MainApplication extends Application { public static SparseArray<UserBean> userArray = new SparseArray<>(); public static Context MainContext; @Override public void onCreate() { super.onCreate(); MainContext = this; }}
可以看到,Activity里已经看不到Model的影子了,Model和View之间的交互全部放在了Presenter里面,很好的隔离了耗时操作了联网等与Activity黏性过高的问题,因为这个例子很经典,也很简单,可以比作一个简单化的登陆demo,但是这个例子还有不足的地方。有时候一个Activity里我们可能会做更多复杂的操作与逻辑,这样的情况下我们可能会写多个Presenter与Model,合理分包,合理的放置逻辑,都是为了实现模块化,独立化的开发思想。
演示效果
其他
对于开发来说,有几个比较重要的个人过程。一个是基本理论,理论你都不懂怎么能让程序正常的跑起来?第二个就是思维,思维影响效率,比如有人做家务,他会先做饭,做完饭再扫地,扫完地再洗衣服,可能有的人就是饭正在烧的时候,他打开了洗衣机洗衣服,然后同时去扫地。这就是思维方式的差异,我希望通过最浅显易懂的方式,来把复杂的问题解释清楚,当然如果实在无法理解,也许就是个人天生的思维逻辑不够完善。
- 从零开始学MVP架构
- 从零开始学架构(一):架构师成长路径
- 【从零开始学BPM,Day1】工作流管理平台架构学习
- 从零开始学
- MVP架构
- MVP架构
- MVP架构
- MVP架构
- MVP架构
- 架构mvp
- MVP-架构
- google官方架构MVP解析与实战-(从零开始搭建android框架系列(3))
- google官方架构MVP解析与实战-(从零开始搭建android框架系列(3))
- google官方架构MVP解析与实战【从零开始搭建android框架系列(3)】
- Google官方MVP+Dagger2架构详解【从零开始搭建android框架系列(6)】
- google官方架构MVP解析与实战-(从零开始搭建android框架系列(3))
- 从零开始做一个有后端,有短信验证,mvp架构,真正的登录注册小项目(一)
- --------------------《洪恩从零开始学日语》---------------------------
- hdu 6229
- 页面跳转时屏幕出现抖动现象
- python3
- 单词游戏: hangman
- 电路分析计算必备数学知识----三角函数
- 从零开始学MVP架构
- app_27305
- 逻辑控制之While循环控制器(While Controller)
- Python 面试问答 Top 25
- Java Integer 127 界限
- Linux配置永久ip
- apicloud各种提示框
- JAVA架构师浅谈JAVA程序员进阶成为架构师的先决条件
- Matlab 完成高斯混合模型聚类