本文MVP的sample实现效果:

  

  github地址:https://github.com/xurui1995/MvpSample

  

  老规矩,在说对MVP模式的理解之前还是要再谈谈MVC模式,了解了MVC的缺点。我们才知道为什么要用MVP。

  关于MVC的图解,我在网上找到了一些图。如下:

    

  MVC模式在开发web或者管理系统中应用很多,我们的View与人交互,人点击鼠标或者输入一些东西时,View会发送相应的指令给Controller,Controller接到指令,再去调用Model的方法去更新数据(大多是对数据的增删改查),Model处理完,View刷新显示

  MVC模式的缺点:

    1:在android中,如果我们要用mvc模式,那么每层代表什么呢?

     你可能会说:View对应android的layout.xml,Model对应android中对数据库的操作对网络等操作放在这里进行,Controller对应的则是Activity!

     你说的都对,但是你不觉得这样的对应关系并不好吗,如果layout.xml对应View,那如果我们想动态的控制添加一些视图控件或者改变背景,那么该怎么办呢?

     答曰:在Activity中添加代码。!!!这就是缺点之一所在:Activity既当爹(View)又当妈(Controller),layout.xml代表的View层控制能力太弱。

    2:再看一遍我们的MVC的结构图,View和Model是互相联系的,存在耦合关系,这就给测试维护带来了难度。当我们想更换项目中的某个零件时,缺发现 太难拆下来!这个零件类的方法散布多处。关于MVC的结构图,忘了在哪听过一句经典的话,写三个字母,M,V,C,随便用线或箭头连字母,最后就是MVC的结构图。

  说完了MVC,该主角登场了,上我们MVP的结构图。

  

  好处不言而喻,View和Model无法通信了。

  View层只负责与View有关的,操作View层时发出的事件传递给Presenter,Presenter去操作Model,操作完Model,再去通知View相应更新。

  关于MVP的更多概念:

  【翻译】Android的MVP设计模式

  MVC,MVP 和 MVVM 的图示

  接下来,看看我们在项目中如何使用MVP模式,这里顺便使用了Retrofit和RXjava,建议你先了解它们的用法。

  首先看我们的需求:输入Github登录名,点击搜索按钮,搜索并显示结果(登录名,昵称, followers,following)

  

  最终的项目结构:

               

   bean类:    

  1. public class User {
  2. private String login;
  3. private String name;
  4. private int followers;
  5. private int following;
  6.  
  7. public int getFollowers() {
  8. return followers;
  9. }
  10.  
  11. public void setFollowers(int followers) {
  12. this.followers = followers;
  13. }
  14.  
  15. public int getFollowing() {
  16. return following;
  17. }
  18.  
  19. public void setFollowing(int following) {
  20. this.following = following;
  21. }
  22.  
  23. public String getLogin() {
  24. return login;
  25. }
  26.  
  27. public void setLogin(String login) {
  28. this.login = login;
  29. }
  30.  
  31. public String getName() {
  32. return name;
  33. }
  34.  
  35. public void setName(String name) {
  36. this.name = name;
  37. }
  38. }

   

    retrofit类主要是封装了利用Retrofit的网络请求 

  1. public interface GithubService {
  2. @GET("/users/{user}")
  3. Observable<User> getUser(@Path("user") String username);
  4. }

  

  1. public class HttpMethods {
  2. public static final String BASE_URL = "https://api.github.com";
  3.  
  4. private static final int DEFAULT_TIMEOUT = 5;
  5.  
  6. private Retrofit retrofit;
  7. private GithubService mGithubService;
  8.  
  9. //构造方法私有
  10. private HttpMethods() {
  11. //手动创建一个OkHttpClient并设置超时时间
  12. OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
  13. httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
  14.  
  15. retrofit = new Retrofit.Builder()
  16. .client(httpClientBuilder.build())
  17. .addConverterFactory(GsonConverterFactory.create())
  18. .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
  19. .baseUrl(BASE_URL)
  20. .build();
  21.  
  22. mGithubService = retrofit.create(GithubService.class);
  23. }
  24. private static class SingletonHolder{
  25. private static final HttpMethods INSTANCE = new HttpMethods();
  26. }
  27.  
  28. //获取单例
  29. public static HttpMethods getInstance(){
  30. return SingletonHolder.INSTANCE;
  31. }
  32.  
  33. public void getUser(Subscriber<User> subscriber ,String loginName){
  34. mGithubService.getUser(loginName)
  35. .subscribeOn(Schedulers.io())
  36. .unsubscribeOn(Schedulers.io())
  37. .observeOn(AndroidSchedulers.mainThread())
  38. .subscribe(subscriber);
  39.  
  40. }
  41. }

    

  接下来思考我们的MVP模式了,一些从我们的View层开始,我们需要先列出和View相关的方法(不涉及逻辑)。

  1.显示xml的试图

2.ProgressDialog显示

  3.ProgressDialog消失

  4.显示错误信息

接下来看具体代码:

  activity_main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:paddingBottom="@dimen/activity_vertical_margin"
  8. android:paddingLeft="@dimen/activity_horizontal_margin"
  9. android:paddingRight="@dimen/activity_horizontal_margin"
  10. android:paddingTop="@dimen/activity_vertical_margin"
  11. >
  12.  
  13. <TextView
  14. android:id="@+id/tv"
  15. android:layout_width="match_parent"
  16. android:layout_height="80dp"/>
  17. <EditText
  18. android:id="@+id/ed_text"
  19. android:layout_centerInParent="true"
  20. android:hint="请输入搜索登录名"
  21. android:layout_width="wrap_content"
  22. android:layout_height="wrap_content"/>
  23. <Button
  24. android:id="@+id/search_btn"
  25. android:text="查询"
  26. android:layout_centerHorizontal="true"
  27. android:layout_below="@+id/ed_text"
  28. android:layout_width="wrap_content"
  29. android:layout_height="wrap_content"/>
  30. </RelativeLayout>

  BaseView,BasePresentor , BaseModel三个接口 

  

  1. public interface BaseView {
  2. void showProgressDialog();
  3. void hideProgressDialog();
  4. void showText(User userbean);
  5. void showErrorMessage(String text);
  6. }

  

  1. public interface BasePresenter<T extends BaseView> {
  2. void attachView(T view);
  3. void detachView();
  4. void searchUser(String loginName);
  5. }

  

  1. public interface BaseModel {
  2. void getUser(Subscriber<User> subscribe,String loginName);
  3. }

  第二个接口interface BasePresenter<T extends BaseView>正是关键,至于为什么,可以用实现类去解释。

  MainActivity实现BaseView接口,作为View层。 

  

  1. public class MainActivity extends AppCompatActivity implements BaseView {
  2.  
  3. @InjectView(R.id.tv)
  4. TextView mTextView;
  5. @InjectView(R.id.search_btn)
  6. Button mButton;
  7. @InjectView(R.id.ed_text)
  8. EditText mEditText;
  9.  
  10. private ProgressDialog dialog;
  11. private MainPresenter mMainPresenter;
  12. @Override
  13. protected void onCreate(Bundle savedInstanceState) {
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.activity_main);
  16. ButterKnife.inject(this);
  17. initView();
  18. mMainPresenter=new MainPresenter();
  19. mMainPresenter.attachView(this);
  20. }
  21.  
  22. /**
  23. * 一些初始化,这里为ProgressDialog的初始化
  24. */
  25. private void initView() {
  26. dialog=new ProgressDialog(this);
  27. dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
  28. dialog.setMessage("正在搜索中");
  29. }
  30.  
  31. @OnClick(R.id.search_btn)
  32. void search(View view){
  33. mMainPresenter.searchUser(mEditText.getText().toString());
  34. }
  35.  
  36. @Override
  37. public void showProgressDialog() {
  38. dialog.show();
  39. }
  40.  
  41. @Override
  42. public void hideProgressDialog() {
  43. dialog.dismiss();
  44. }
  45.  
  46. @Override
  47. public void showText(User userbean) {
  48. String temp=getResources().getString(R.string.user_format);
  49. String str=String.format(temp,userbean.getLogin(),userbean.getName(),userbean.getFollowers(),userbean.getFollowing());
  50. mTextView.setText(str);
  51. }
  52.  
  53. @Override
  54. public void showErrorMessage(String text) {
  55. Toast.makeText(this,text,Toast.LENGTH_SHORT).show();
  56. }
  57.  
  58. @Override
  59. protected void onDestroy() {
  60. super.onDestroy();
  61. if(mMainPresenter!=null)
  62. mMainPresenter.detachView();
  63. }
  64. }

  当点击Button产生事件时,是将逻辑交给MainPresenter去处理的,对应关系  V  ——>  P

  下面看MainPresenter代码和Model代码。

  

  1. public class MainPresenter implements BasePresenter {
  2. private BaseView mMainView;
  3. private MainModel mModel;
  4.  
  5. public MainPresenter() {
  6. mModel=new MainModel();
  7. }
  8.  
  9. @Override
  10. public void attachView(BaseView view) {
  11. mMainView=view;
  12. }
  13.  
  14. @Override
  15. public void detachView() {
  16. mMainView=null;
  17. }
  18. @Override
  19. public void searchUser(String loginName) {
  20. if(TextUtils.isEmpty(loginName.trim())){
  21. mMainView.showErrorMessage("请输入合法登录名");
  22. return;
  23. }
  24. if (mModel!=null){
  25. mModel.getUser(new Subscriber<User>() {
  26. @Override
  27. public void onStart() { //先显示对话框
  28. mMainView.showProgressDialog();
  29. }
  30.  
  31. @Override
  32. public void onCompleted() { //请求结束,对话框消失
  33. mMainView.hideProgressDialog();
  34.  
  35. }
  36.  
  37. @Override
  38. public void onError(Throwable e) { //error时
  39. mMainView.showErrorMessage("搜索失败");
  40. }
  41.  
  42. @Override
  43. public void onNext(User user) {
  44. mMainView.showText(user);
  45. }
  46. },loginName);
  47. }
  48.  
  49. }
  50. }

 

  1. public class MainModel implements BaseModel{
  2. @Override
  3. public void getUser(Subscriber<User> subscriber ,String loginName) {
  4. HttpMethods.getInstance().getUser(subscriber,loginName);
  5. }
  6. }

  这里的Model实现类较为简单,直接使用了封装好的HttpMethods的方法。(Model可以理解为一个仓库管理员,我们的网络也能理解为一个大的仓库)。

  在MainPresenter中我们其实是使用了Model的方法,即P——>M

  然后用Rxjava的观察者观察结果,再去调用View的方法刷新界面,即P——>V

  

  这时候回过来头来看我们的MVP图,是不是一模一样?(如何想要进阶mvp,可以试试契约类)

       

  

  

MVP模式入门(结合Rxjava,Retrofit)的更多相关文章

  1. MVP模式入门案例

    随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Model只关系数据的处 ...

  2. Android开发学习--MVP模式入门

    1.模型与视图完全分离,我们可以修改视图而不影响模型2.可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部3.我们可以将一个Presenter用于多个视图,而不需要改变Pr ...

  3. MVP架构下解决 RxJava 自动解绑问题

    背景 MVP 模式下使用 RxJava 处理网络访问的回调,当数据返回时 Presenter 调用绑定的 View 的方法. 定义 BasePresenter 如下: public class Bas ...

  4. RxJava+Retrofit+MVP构建的App——聚合资讯

    RtfRxMVP 聚合资讯APP,提供热点资讯,天气预报以及笑话精选服务,使用 Retrofit + RxJava + MVP 构建代码. Hello U 这是我的一个练习项目,第一次尝试运用 MVP ...

  5. 开发 Material Design+RxJava+Retrofit+MVP App 参考资料

    前言     在开发一个基于 Material Design+RxJava+Retrofit+MVP 框架的 App 过程中学习的资料整理 —— 由G军仔分享 这里记录了我开发 大象 项目时,所学习的 ...

  6. android打飞机游戏、MVP句子迷App、悬浮窗、RxJava+Retrofit、加载动画、定制计划App等源码

    Android精选源码 微信打飞机 android进度设置加载效果源码 Android新手引导库EasyGuide MVP-好看又好用的句子迷客户端 XFloatView 一个简易的悬浮窗实现方案 a ...

  7. android完整资讯App、Kotlin新闻应用MVP + RxJava + Retrofit + Dagger2、优雅区间选择器等源码

    Android精选源码 Android完整资讯客户端源码 android展示注册进度效果源码 Android Wifi热点数据传输Socket 通信示例源码 Android Dota的辅助信息app源 ...

  8. 手把手带你走进MVP +Dagger2 + DataBinding+ Rxjava+Retrofit 的世界

    0.0 Android开发现在的变化用一个词来形容就是 :翻天覆地 越来越多的项目使用了MVP + Rxjava+Retrofit +Dagger2 + DataBinding等等东西.. 但是这些东 ...

  9. Rxjava + retrofit + dagger2 + mvp搭建Android框架

    最近出去面试,总会被问到我们项目现在采用的什么开发框架,不过据我的经验网络框架(volley)+图片缓存(uIl)+数据库(orm)+mvp,不过现在这套框架比较好了,现在采用什么呢?Rxjava + ...

随机推荐

  1. UVA-1331 Minimax Triangulation 区间dp 计算几何 三角剖分 最大三角形最小化

    题目链接:https://cn.vjudge.net/problem/UVA-1331 题意 给一个任意多边形,把它分为多个三角形. 求某方案中最大的三角形是各方案中最小的面积的三角形面积. 思路 学 ...

  2. Java XSSF 导出excel 工具类

    参数解释: title:导出excel标题.headers 导出到excel显示的列头. columns 对应数据库字段 .list 导出数据1.pox中添加依赖 <dependency> ...

  3. 洛谷 P1417 烹调方案 (01背包拓展)

    一看到这道题就是01背包 但是我注意到价值和当前的时间有关. 没有想太多,直接写,0分 然后发现输入方式不对-- 改了之后只有25分 我知道wa是因为时间会影响价值,但不知道怎么做. 后来看了题解,发 ...

  4. hbase报错Could not initialize class org.apache.hadoop.hbase.protobuf.ProtobufUtil

    Caused by: java.lang.RuntimeException: java.io.IOException: java.lang.reflect.InvocationTargetExcept ...

  5. MySQL 以及 Python 实现排名窗体函数

    大部分数据库都提供了窗体函数.比方RANK,ROW_NUMBER等等. MySQL 这方面没有直接提供.可是能够变相的实现.我曾经写了row_number 的实现,今天有时间把 rank 的实现贴出来 ...

  6. 芒果TV真实视频地址解析

    本文旨在互相学习,请勿滥用 若有幸被您引用请附加地址来源http://blog.csdn.net/feige2008/article/details/37579051 文章主要解析芒果TV的视频真实地 ...

  7. codevs1052

    题目地址:http://codevs.cn/problem/1053/ 分析: 模拟 代码: var s:string; a:array['a'..'z'] of longint; i,j,t,n:l ...

  8. poj_2352树状数组

    因为y已经排好序了,用x坐标建立一维树状数组 #include<iostream> #include<cstdio> #include<cstring> using ...

  9. python 统计文件top IP

    lines = ''' 1.2.2.3 1.21.29.19.... ''' cnt = {} for line in lines.split(): if line not in cnt: cnt[l ...

  10. Automation testing tool comparison - UFT & CodedUITest

    Ease of Use - Recording and Playback Functionality UFT provides 4 models to record a new test. Norma ...