设计模式笔记之四:MVP+Retrofit+RxJava组合使用

本博客转自郭霖公众号:http://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650236866&idx=1&sn=da666831f67303eeb7a57c1591204b43&scene=24&srcid=0910wJAKSLdsEFTBKwKfTNor#wechat_redirect

http://blog.csdn.net/qq_27778869/article/details/52121208


MVP

MVP 是基于 MVC 的改进,相信大家都是从 MVC 走过的,可能很多人还会在项目中使用 MVC,我们传统的 MVC xml布局 充当就是 视图层(View)业务层兼模型层 的一些业务处理需要在我们 Activity 或 Fragment 中进行处理然后更新视图层。由于xml定义好的布局,一旦加载之后,只能通过动态更新,那么视图层和Model就建立了联系,因此二者的耦合度就提高了,那么一旦修改了其中的一个就有可能对另一产生影响。

同时所有的操作在我们的 Controller 中进行处理,Controller 就会显得十分的臃肿,可读性就降低了,导致后期的项目维护成本提高了不少。很多时候你需要和团队一起开发项目,如果你的同事有一天在你请假或者想修改功能的时候发现一个Activity都有上千行甚至更多的时候,他开始慌了,他慌的时候如果还找到你的话,你可能也慌了。有了 MVP 之后,妈妈再也不用担心我会慌了!

MVP model层 依然不变,只不过之前充当 Controller Activity或者Fragment 就变身为了 View层,而业务逻辑的实现是在我们的 Presenter 中。简单介绍完了 MVP,光说不练,一点效果都没有的,下面我们来进行 MVP 的三部曲。

本次案例是在进入程序的时候访问服务器的指定接口来获取当前服务器中apk的版本号,通过对比和当前应用程序的版本号,如果有新版本弹出一个土司提示用户更新,功能就这么简单。

  • 视图层需要哪些更新UI的操作?可能大家会好奇我为什么会问这个,这里我留下一个悬念,待会给大家细讲。这个问题的答案是弹出一个土司提示用户更新。
  • 怎么进行更新UI前的操作?
  • 何时告知视图层进行UI更新?

结合上面的三个问题,我们根据需求设计代码:

1. 定义一个 MvpView 的接口:

1 public Interface MvpView {
2 //提示更新
3 void showMessage();
4
5 }

2. 定义一个 Model 类:

 1 public class MvpModel{
 2   /*从服务器获取的apk版本*/
 3     private String newApkVersion;
 4 //这里我就随便给出一个,正确与否我就不得而知 这里面需要注意的query是跟上请求的参数,通过GET方法来请求的 ,你可能这会问我,不是说不知道正不正确的吗,那还解释这么多?不好意思哈,我这里说明好是为了下面讲到Retrofit 做铺垫的
 5     public static final String GET_NEW_VER_URL="http://192.168.1:8080/app/index/type?version=query";
 6     public String getNewApkVersion() {
 7         return newApkVersion;
 8     }
 9
10     public void setNewApkVersion(String newApkVersion) {
11         this.newApkVersion = newApkVersion;
12
13 }

3. 定义一个基类 BasePresenter(当然大家也可以不用这么做):

 1 public abstract class BasePresenter<T> {
 2
 3     /*这个基类的Presenter 主要的作用就是将当前Presenter持有的view 在合适的时候给清除掉*/
 4     public T mView ;
 5     public void attach(T mView){
 6
 7         this.mView=mView;
 8
 9
10     }
11
12
13     public void dettach(){
14
15         mView=null;
16
17  }
18
19 }

4. 定义一个实际操作的 MvpPresenter

 1 public class MvpPresenter extends BasePresenter<MvpView> {
 2     private MvpModel mMvpModel;
 3     private Context mContext;
 4     private RequestQueue mRequestQueue;
 5     //这里重写当前的构造函数 因为我们需要获取程序的版本,因此需要一个上下文对象
 6     public MvpPresenter (Context mContext) {
 7         this.mContext = mContext;
 8         //当前的Mvp模式的讲解我是采用Volley进行网络请求的所以 就封装了一个VolleyManager用于获取唯一的RequestQueue对象
 9         mRequestQueue = VolleyManager.getInstance(mContext).getRequestQueue();
10         //对业务层初始化为后面获取的apk版本进行存放
11         mUpdateModel = new MvpModel();
12    }
13    //由于逻辑处理放到我们的Presenter中了,因此我们需要将在Activity的onResume 时候进行版本的检查
14    public void onResume(){
15
16
17     }
18
19     }

5. 开始视图层的构建了,不过在之前我们先创建一个 BaseMvpActivity 用于统一化管理我们的 MVP模式 的Activity的构建:

 1 public abstract class BaseMvpActivity<V,T extends BasePresenter<V> > extends AppCompatActivity {
 2
 3
 4
 5  /*定义一个Presenter 用于解绑持有的View
 6     *
 7     * 在onCreate进行初始化Presenter的操作
 8     * 在onResume中进行绑定
 9     * 在onDestroy 中进行解绑
10     *
11     * */
12     public T presenter;
13     @Override
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         presenter=initPresenter();
17
18     }
19
20     @Override
21     protected void onResume() {
22         super.onResume();
23         presenter.attach((V)this);
24     }
25
26      @Override
27         protected void onDestroy() {
28         super.onDestroy();
29         presenter.dettach();
30      }
31
32     /* 这里是适配为不同的View 装载不同Presenter*/
33     public abstract T initPresenter();
34
35
36 }

6. 正式写我们的应用Activity了(当前Activity的布局中仅有一个TextView):

 1 public class MvpActivity extends BaseMvpActivity<MvpView,MvpPresenter> implements MvpView{
 2     @Bind(R.id.tvShow)
 3     TextView tvMsg;
 4      @Override
 5     protected void onCreate(Bundle savedInstanceState) {
 6         super.onCreate(savedInstanceState);
 7
 8         setContentView(R.layout.activity_update);
 9         ButterKnife.bind(this);
10        }
11     @Override
12     protected void onResume() {
13         super.onResume();
14        presenter.onResume();
15     }
16      @Override
17     public MvpPresenter initPresenter() {
18         return new MvpPresenter (getApplicationContext());
19     }
20      @Override
21
22     public void showMessage(){
23
24     tvMsg.setText("有新版本需更新!");
25
26     Toast.makeText(getApplicationContext(),"更新版本啦",Toast.LENGTH_LONG).show();
27
28
29     }
30
31
32
33
34
35
36
37
38 }

7. 看到上面的 MvpActivity 是不是觉得代码很清爽,那还不是把业务处理的逻辑丢给了 Presenter了,好了我们来具体看看 MvpPresenter 怎么写:

 1 //在前面贴出的代码中添加
 2 pulic void onResume(){
 3
 4 getVerFromServer();
 5
 6
 7 }
 8 private void getVerFromServer(){
 9
10     JsonObjectRequest jsonRequest = new JsonObjectRequest(Request.Method.GET, MvpModel.GET_NEW_VERSION ,null, new Response.Listener<JSONObject>() {
11             @Override
12             public void onResponse(JSONObject response) {
13                 Log.e("请求版本返回结果为:",response.toString());
14
15                                 try {
16                     mUpdateModel.setNewApkVersion(response.getJSONObject("data").getString("version"));
17             //如果从服务器获取的版本和当前的版本相同,就可提示用户了
18             if(mUpdateModel.getNewApkVersion.equals(getCurrentVer())){
19              //这里就是合适的更新UI时间,通过这里把更新的实际传递出去
20                 mView.showMessage();
21                                 } catch (JSONException e) {
22                     e.printStackTrace();
23                 }
24
25             }
26         }, new Response.ErrorListener() {
27             @Override
28             public void onErrorResponse(VolleyError error) {
29
30             }
31         });
32         jsonRequest.setTag("getVer");
33         mRequestQueue.add(jsonRequest);
34
35
36 }
37 private String getCurrentVer(){
38  String verName="";
39         try {
40             verName=mContext.getPackageManager().getPackageInfo(context.getPackageName(),0).versionName;
41         } catch (PackageManager.NameNotFoundException e) {
42             e.printStackTrace();
43         }
44         Log.e("apkVer",verName);
45         return verName;
46
47 }

Retrofit简单介绍及使用

相信大家在开发过程中被这个字眼给冲击过不少次,具体 Retrofit 是什么这里我就不详细介绍了,我们只针对它的简单应用来讲解:

1. 首先需要创建一个接口如 RetrofitCall,因为 Retrofit 是通过注解的形式构建方法的,下面我们来写一下:

1 public interface RetrofitCall{
2     // 我们把之前定义好的api接口 拿来  http://192.168.1:8080/app/index/type?version=query
3     //这里我先简单给大家介绍一下 Retrofit 请求网络的接口形式要满足RESTful 形式(有不了解的可自填坑) 不够构成一般是这样的[协议类型:][//主机地址加端口(或者域名)][具体目录][请求参数]
4     //所以这个接口的具体目录(path)为app/index/type 也就是下面这个GET注解中应该填入的
5     @GET("app/index/type")
6     Call<VersionBean> getVer(@Query(version) String ver);
7     //如果有读者不知道这个VersionBean怎么生成的可以查看我的博客有一篇讲Retrofit的 其实就是利用GSONFromat 来实现的
8
9 }

2. 注册网络访问(这里的代码是在 Presenter 实现的):

1 Retrofit mRetrofit =new Retrofit.Builder()
2                     //这里为主机加端口(或域名)
3                   .baseUrl("http://192.168.1:8080/")
4                   .clent(new OkHttpClient())
5                   .addConverterFactory(GsonConverterFactory.create())
6                   .build();

3. 创建自定义接口实例并执行异步网络请求:

 1 RetrofitCall call=mRetrofit.create(RetrofitCall.class);
 2 //这里需要把请求的参数填入
 3 Call<VersionBean> myCall=call.getVer("1");
 4 //异步执行
 5 maCall.enqueue(new Callback<VersionBean>(){
 6 @Override
 7        public void onResposne(Call<VersionBean>call,retrofit2.Response<VersionBean> response)    {
 8
 9
10         if(response.body().getData().getVersion().equals(getCurrentVe   r())){
11
12           mView.showMessage();
13           }
14 }
15             @Override
16             public void onFailure(Call<VersionBean> call, Throwable t) {
17             Log.e("callerro+"------------>"+t);
18             }
19
20 });

通过RxJava改进Retrofit

RxJava 是一个异步操作的库,主要采用的观察者模式,在这里我只是简单的介绍,需要详细了解可以参考抛物线这篇:

给Android开发工程师的一篇关于RxJava的详解(这个已经推荐好几次了,值得一看呐)

http://gank.io/post/560e15be2dca930e00da1083

在这里我就不作过多介绍了,我们来演示 Retrofit 依靠 RxJava 来改进上面的代码,我们在 RetrofitCall 中添加一个新的注解:

1 @GET("app/index/type")
2 Observable<VersionBean> getVerByRxJavaWithRetrofit(@Query("version") String ver);

接着在 Presenter 中填入如下的方法:

 1 private void requestDataByRxJavaWithRetrofit(){
 2     Retrofit mRxjavaRetrofit= new Retrofit.Builder()
 3                         .baseUrl("http://192.168.1:8080/")
 4                         //由于需要转为Observable 需要添加RxJavaCallAdapterFactory
 5                         .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 6                         .addConverterFactory(GsonConverterFactory.create())
 7                         .build();
 8     RetrofitCall call= mRxjavaRetrofit.create(RetrofitCall.class);
 9     call.getVerByRxJavaWithRetrofit(""1)
10     //指定时间消费在主线程
11     .observeOn(AndroidSchedulers.mainThread())
12     //事件产生在新线程
13     .subscribeOn(Schedulers.newThread())
14     //指定一个观察者
15     .subscribe(new Observer<Version>(){
16                     @Override
17                     public void onCompleted() {
18
19                     mView.showMessage();
20                       }
21
22                     @Override
23                     public void onError(Throwable e) {
24
25                     }
26                     /*这个时候是订阅者需要跟新UI的时间了通知它更新*/
27                     @Override
28                     public void onNext(LogoBean logoBean) {
29                         /*这里先不做判断*/
30
31                     }
32
33
34     }       );
35
36 }

总结

上面对这三者的结合使用有了一个直观的介绍,其实 MVP模式 可以理解为更新UI需要什么操作,什么时候开始更新UI,怎么更新UI;而我们的 MVP模式 就是把这三种状态巧妙地分开,因此会让思路显得很清晰。

RxJava 正式基于这种设计,被观察者通过被订阅的形式在自己有新动态的时候告知观察者我改变了,剩下的就交给观察者做自己应该做的事情了!这样的设计模式很符合我们需求,也很利于团队开发,换个模式你会觉得效率大大提高,让我们一起加入 MVP+RxJava+Retrofit 的队列之中吧!

时间: 2024-10-13 23:49:23

设计模式笔记之四:MVP+Retrofit+RxJava组合使用的相关文章

mvp+retrofit+rxjava

引用 "retrofit" : "com.squareup.retrofit2:retrofit:2.0.1", "retrofit-adapter" : "com.squareup.retrofit2:adapter-rxjava:2.0.1", "retrofit-converter" : "com.squareup.retrofit2:converter-gson:2.0.1",

Android-MVP+Retrofit+Rxjava实现一个知乎日报客户端

使用MVP+Retrofit+Rxjava实现一个知乎日报客户端,界面基于Material design,还没有全部完成orz,,放假太懒 效果图 开源项目 name introduction butterknife Annotate fields with @BindView and a view ID for Butter Knife to find and automatically cast the corresponding view in your layout. MaterialT

Asp.net设计模式笔记之一:理解设计模式

GOF设计模式著作中的23种设计模式可以分成三组:创建型(Creational),结构型(Structural),行为型(Behavioral).下面来做详细的剖析. 创建型 创建型模式处理对象构造和引用.他们将对象实例的实例化责任从客户代码中抽象出来,从而让代码保持松散耦合,将创建复杂对象的责任放在一个地方,这遵循了单一责任原则和分离关注点原则. 下面是“创建型”分组中的模式: 1.Abstract Factory(抽象工厂)模式:提供一个接口来创建一组相关的对象. 2.Factory Met

优雅地使用Retrofit+RxJava(二)

前言 在我上一篇讲Retrofit+RxJava在MVP模式中优雅地处理异常(一)中,发现很多网友发邮箱给我表示期待我的下一篇文章,正好趁着清明假期,我就写写平时我在使用RxJava+Retrofit怎么去灵活地处理一些场景.比如说一些比较常见的场景: 网络请求过程中token的处理 网络请求数据的加密与解密 为每个请求添加固定的头部,比如说当前版本号,Rsa的密钥等等 规范化每个网络请求,让代码只写一次 我自己平时对代码的简洁性要求非常高,所以retrofit+rxjava正好切中了我的痛点,

(CZ深入浅出Java基础)设计模式笔记

一.面向对象思想设计原则 1.单一职责原则 其实就是开发人员经常说的"高内聚,低耦合",也就是说,每个类应该只有一个职责,对外只能提供一种功能,而引起类变化的原因应该只有一个.在设计模式中,所有的设计模式都遵循这一原则. 2.开闭原则 核心思想是:一个对象对扩展开放,对修改关闭.其实开闭原则的意思就是:对类的改动是通过增加代码进行的,而不是修改现有代码.也就是说软件开发人员一旦写出了可以运行的代码,就不应该去改动它,而是要保证它能一直运行下去,如何能够做到这一点呢?这就需要借助于抽象和

我们为什么要把Dagger2,MVP以及Rxjava引入项目中?

1Why? 毫无疑问在Android开发圈中这三个技术是经常被提及的,如此多的文章和开源项目在介绍他们,使用他们,开发者也或多或少的被带动起来在自己的项目中使用他们,但是使用他们之前我们知道为什么要使用他们,他们能给我们带来什么好处吗,还是只是跟随潮流 其实我们大多数项目中是使用不到他们的,或者说对这些技术的需求不是很大,为什么这么说呢? 大多数的开发者其实都是在开发功能模块比较少的小项目,对于这些项目来说,其实使用这些技术带来的好处相对于在开发时的所付出的时间来说其实性价比并不高,因为学习这些

基于Retrofit+RxJava的Android分层网络请求框架

目前已经有不少Android客户端在使用Retrofit+RxJava实现网络请求了,相比于xUtils,Volley等网络访问框架,其具有网络访问效率高(基于OkHttp).内存占用少.代码量小以及数据传输安全性高等特点. Retrofit源码更是经典的设计模式教程,笔者已在之前的文章中分享过自己的一些体会,有兴趣的话可点击以下链接了解:<Retrofit源码设计模式解析(上)>.<Retrofit源码设计模式解析(下)> 但在具体业务场景下,比如涉及到多种网络请求(GET/PU

[设计模式] .NET设计模式笔记 - 有多少种设计模式

.NET下的23中设计模式. ※创建型模式篇 ●单件模式(Single Pattern) ●抽象工厂模式(Abstract Factory) ●建造者模式(Builder Pattern) ●工厂方法(Factory Method) ●原型模式(Protype Pattern) ※结构型模式篇 ●适配器模式(Adapter Pattern) ●桥接模式(Bridge Pattern) ●装饰模式(Decorator Pattern) ●组合模式(Composite Pattern) ●外观模式(

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先 本篇名言:"生活真象这杯浓酒 ,不经三番五次的提炼呵 , 就不会这样一来可口 ! -- 郭小川" 继续看下广度优先的遍历,上篇我们看了深度遍历是每次一个节点的链表是走到底的. 欢迎转载,转载请标明出处:http://write.blog.csdn.net/postedit/47029275 1.  原理 首先,从图的某个顶点v0出发,访问了v0之后,依次访问与v0相邻的未被访问的顶点,然后分别从这些顶点出发,广度优先遍历,直至所有的