MVP模式入门(结合Rxjava,Retrofit)

  本文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类:    

public class User {
    private String login;
    private String name;
    private int followers;
    private int following;

    public int getFollowers() {
        return followers;
    }

    public void setFollowers(int followers) {
        this.followers = followers;
    }

    public int getFollowing() {
        return following;
    }

    public void setFollowing(int following) {
        this.following = following;
    }

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

   

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

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

  

public class HttpMethods {
    public static final String BASE_URL = "https://api.github.com";

    private static final int DEFAULT_TIMEOUT = 5;

    private Retrofit retrofit;
    private GithubService mGithubService;

    //构造方法私有
    private HttpMethods() {
        //手动创建一个OkHttpClient并设置超时时间
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        retrofit = new Retrofit.Builder()
                .client(httpClientBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();

        mGithubService = retrofit.create(GithubService.class);
    }
    private static class SingletonHolder{
        private static final HttpMethods INSTANCE = new HttpMethods();
    }

    //获取单例
    public static HttpMethods getInstance(){
        return SingletonHolder.INSTANCE;
    }

    public void getUser(Subscriber<User> subscriber ,String loginName){
        mGithubService.getUser(loginName)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);

    }
}

    

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

  1.显示xml的试图

2.ProgressDialog显示

  3.ProgressDialog消失

  4.显示错误信息

接下来看具体代码:

  activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
  >

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="80dp"/>
    <EditText
        android:id="@+id/ed_text"
        android:layout_centerInParent="true"
        android:hint="请输入搜索登录名"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/search_btn"
        android:text="查询"
        android:layout_centerHorizontal="true"
        android:layout_below="@+id/ed_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</RelativeLayout>

  BaseView,BasePresentor , BaseModel三个接口 

  

public interface BaseView {
    void showProgressDialog();
    void hideProgressDialog();
    void showText(User userbean);
    void showErrorMessage(String text);
}

  

public interface BasePresenter<T extends BaseView> {
    void attachView(T view);
    void detachView();
    void searchUser(String loginName);
}

  

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

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

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

  

public class MainActivity extends AppCompatActivity implements BaseView {

    @InjectView(R.id.tv)
    TextView mTextView;
    @InjectView(R.id.search_btn)
    Button mButton;
    @InjectView(R.id.ed_text)
    EditText mEditText;

    private  ProgressDialog dialog;
    private MainPresenter mMainPresenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.inject(this);
        initView();
        mMainPresenter=new MainPresenter();
        mMainPresenter.attachView(this);
    }

    /**
     * 一些初始化,这里为ProgressDialog的初始化
     */
    private void initView() {
        dialog=new ProgressDialog(this);
        dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        dialog.setMessage("正在搜索中");
    }

    @OnClick(R.id.search_btn)
    void search(View view){
        mMainPresenter.searchUser(mEditText.getText().toString());
    }

    @Override
    public void showProgressDialog() {
        dialog.show();
    }

    @Override
    public void hideProgressDialog() {
        dialog.dismiss();
    }

    @Override
    public void showText(User userbean) {
        String temp=getResources().getString(R.string.user_format);
        String str=String.format(temp,userbean.getLogin(),userbean.getName(),userbean.getFollowers(),userbean.getFollowing());
        mTextView.setText(str);
    }

    @Override
    public void showErrorMessage(String text) {
        Toast.makeText(this,text,Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mMainPresenter!=null)
        mMainPresenter.detachView();
    }
}

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

  下面看MainPresenter代码和Model代码。

  

public class MainPresenter implements BasePresenter {
    private BaseView mMainView;
    private MainModel mModel;

    public MainPresenter() {
        mModel=new MainModel();
    }

    @Override
    public void attachView(BaseView view) {
        mMainView=view;
    }

    @Override
    public void detachView() {
        mMainView=null;
    }
    @Override
    public void searchUser(String loginName) {
        if(TextUtils.isEmpty(loginName.trim())){
            mMainView.showErrorMessage("请输入合法登录名");
            return;
        }
        if (mModel!=null){
            mModel.getUser(new Subscriber<User>() {
                @Override
                public void onStart() {  //先显示对话框
                    mMainView.showProgressDialog();
                }

                @Override
                public void onCompleted() {  //请求结束,对话框消失
                    mMainView.hideProgressDialog();

                }

                @Override
                public void onError(Throwable e) {   //error时
                    mMainView.showErrorMessage("搜索失败");
                }

                @Override
                public void onNext(User user) {
                    mMainView.showText(user);
                }
            },loginName);
        }

    }
}

 

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

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

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

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

  

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

       

  

  

时间: 2025-01-19 14:30:11

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

MVP模式入门案例

随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Model只关系数据的处理,基于MVC概念的MVP(Model-View-Presenter)模式应运而生. 四个要素: (1)View:负责绘制UI元素.与用户进行交互(在Android中体现为Activity); (2)View interface:需要View实现的接口,View通过View interface与Pr

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

1.模型与视图完全分离,我们可以修改视图而不影响模型2.可以更高效地使用模型,因为所有的交互都发生在一个地方--Presenter内部3.我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑.这个特性非常的有用,因为视图的变化总是比模型的变化频繁.4.如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试) 下面示例一个小案例: 项目架构: 首先bean层: User.java public class User { privat

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

前言 在开发一个基于 Material Design+RxJava+Retrofit+MVP 框架的 App 过程中学习的资料整理 —— 由G军仔分享 这里记录了我开发 大象 项目时,所学习的开发资料以及参考的开源项目,稍微整理了一下,全当笔记记录,跟大家一起分享,也许能给正在使用 RxJava + Retrofit + MVP + Material Design 框架开发的人一个参考学习,如果有人从我分享的资料当中学习到东西,那是我的荣幸,希望大家能与我一起努力. 之前看到很多人都使用 RxJ

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

0.0 Android开发现在的变化用一个词来形容就是 :翻天覆地 越来越多的项目使用了MVP + Rxjava+Retrofit +Dagger2 + DataBinding等等东西.. 但是这些东西对于木有用过的同学们开起来还是比较头疼的. 转载请标明出处:http://blog.csdn.net/wingichoy/article/details/51981756 网上有很多介绍他们的教程,但是都比较详细(我听到有童鞋问:详细还不好?? 其实他们最好的学习方式还是边敲边踩坑边学,一下介绍的

[android架构篇]mvp+rxjava+retrofit+eventBus

android架构篇 mvp+rxjava+retrofit+eventBus 高层不应该知道低层的细节,应该是面向抽象的编程.业务的实现交给实现的接口的类.高层只负责调用. 首先,要介绍一下一个项目中好架构的好处:好的软件设计必须能够帮助开发者发展和扩充解决方案,保持代码清晰健壮,并且可扩展,易于维护,而不必每件事都重写代码.面对软件存在的问题,必须遵守SOLID原则(面向对象五大原则),不要过度工程化,尽可能降低框架中模块的依赖性. 之前的一段时间,学习了一些新的技术,并把自己关注的技术整合

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

一  MVC模式: M:model,业务逻辑 V:view,对应布局文件 C:Controllor,对应Activity 项目框架: 代码部分: layout文件(适用于MVC和MVP两个Demo): <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" and

Android 架构设计实现——MVP模式

转载请注明出处:http://blog.csdn.net/smartbetter/article/details/70853135 随着 UI 创建技术的功能日益增强,UI 层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让 View 专注于处理数据的可视化以及与用户的交互,同时让 Model 只关系数据的处理,基于 MVC(Model View Controller) 模式的 MVP(Model-View-Presenter) 模式应运而生.目前MVP模式在

MVP模式(2) 你真的理解下抽象类和接口吗??

转载请注明出处:王亟亟的大牛之路 礼拜5下午,有一些小伙伴在讨论关于"我对MVP的理解啊","我对RxJava,RxAndroid的理解啊"等等.在交流中发现,其实我们往往在实际开发中有意无意的都可能出现某个类特别的繁杂,代码特别的多,而且其实很多都是重复的,但是又没有办法,诸如一大堆回调. 可能在项目构建之初,想着我要如何如何去实现,如何如何优化代码结构,逻辑等等,可是因为理解或者业务繁重等各个因素,导致到后来还是挤成一坨龙猫,像这样(麦麦胖的脚都看不见了,臃肿,

Rxjava+ReTrofit+okHttp深入浅出-终极封装

Rxjava+ReTrofit+okHttp深入浅出-终极封装 背景: 学习Rxjava和retrofit已经很长时间了,功能确实很强大,但是使用起来还是有点复杂,代码的重复性太高,所以决定把基于retrofit和rxjava的处理统一封装起来,实现的功能: 1.Retrofit+Rxjava+okhttp基本使用方法 2.统一处理请求数据格式 3.统一的ProgressDialog和回调Subscriber处理 4.取消http请求 5.预处理http请求 5.返回数据的统一判断 效果: 封装