添加请求头 retrofit_RxJava 与 Retrofit 结合的最佳实践

前言

RxJava和Retrofit也火了一段时间了,不过最近一直在学习ReactNative和Node相关的姿势,一直没有时间研究这些新东西,最近有个项目准备写,打算先用Android写一个Demo出来,却发现Android的世界发生了天翻地覆的变化,EventBus和OKHttp啥的都不见了,RxJava和Retrofit是什么鬼?

好吧,到Github上耐着性子看过了RxJava和Retrofit的介绍和几个Demo,原来Android的大神Jake Wharton为Retrofit这个项目贡献了这么多的代码,没有道理不用了。

如果你对RxJava不熟悉请先看给 Android 开发者的 RxJava 详解这篇文章。

如果你对Retrofit不熟悉就先看Retrofit官网。

当然也有很多RxJava与Retrofit的文章,但是我觉得很多大家都很纠结的功能都没有被总结出来,所以才有了此篇文章。

欢迎大家拍砖。

接下来进入正文,我是从下面几个角度去思考RxJava与Retrofit结合的。

  1. RxJava如何与Retrofit结合
  2. 相同格式的Http请求数据该如何封装
  3. 相同格式的Http请求数据统一进行预处理
  4. 如何取消一个Http请求 -- 观察者之间的对决,Oberver VS Subscriber
  5. 一个需要ProgressDialog的Subscriber该有的样子

1.RxJava如何与Retrofit结合

1.1 基本页面

先扔出build.gradle文件的内容

dependencies {      compile fileTree(dir: 'libs', include: ['*.jar'])      testCompile 'junit:junit:4.12'      compile 'com.android.support:appcompat-v7:23.2.0'      compile 'io.reactivex:rxjava:1.1.0'      compile 'io.reactivex:rxandroid:1.1.0'      compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'      compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'      compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'      compile 'com.google.code.gson:gson:2.6.2'      compile 'com.jakewharton:butterknife:7.0.1'}

也就是说本文是基于RxJava1.1.0和Retrofit 2.0.0-beta4来进行的。添加rxandroid是因为rxjava中的线程问题。

下面先搭建一个基本的页面,页面很简单,先来看文件目录结构

36bae9b4c44d6a77b1a4457f39e2de68.png

activity_main.xml的代码如下:

<?xml version="1.0" encoding="utf-8"?>

MainActivity.java的代码如下:

package com.queen.rxjavaretrofitdemo.activity;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.widget.Button;import android.widget.TextView;import com.queen.rxjavaretrofitdemo.R;import butterknife.Bind;import butterknife.ButterKnife;import butterknife.OnClick;public class MainActivity extends AppCompatActivity {      @Bind(R.id.click_me_BN)      Button clickMeBN;      @Bind(R.id.result_TV)      TextView resultTV;      @Override      protected void onCreate(Bundle savedInstanceState)       {            super.onCreate(savedInstanceState);            setContentView(R.layout.activity_main);            ButterKnife.bind(this);      }      @OnClick(R.id.click_me_BN)      public void onClick()       {        getMovie();      }      //进行网络请求      private void getMovie()      {      }}

注意不要忘记加网络权限

1.2 只用Retrofit

我们准备在getMovie方法中进行网络请求,我们先来看看只使用Retrofit是如何进行的。

我们使用豆瓣电影的Top250做测试连接,目标地址为

https://api.douban.com/v2/movie/top250?start=0&count=10

至于返回的数据格式,大家自己访问下链接就看到了,太长就不放进来了。

首先我们要根据返回的结果封装一个Entity,暂命名为MovieEntity,代码就不贴了。

接下来我们要创建一个接口取名为MovieService,代码如下:

public interface MovieService {      @GET("top250")      Call getTopMovie(@Query("start") int start, @Query("count") int count);}

回到MainActivity之中,我们来写getMovie方法的代码

//进行网络请求private void getMovie(){      String baseUrl = "https://api.douban.com/v2/movie/";      Retrofit retrofit = new Retrofit.Builder()                                  .baseUrl(baseUrl)                                  .addConverterFactory(GsonConverterFactory.create())                                  .build();      MovieService movieService = retrofit.create(MovieService.class);      Call call = movieService.getTopMovie(0, 10);      call.enqueue(new Callback()       {              @Override                public void onResponse(Call call, Response response)                 {                  resultTV.setText(response.body().toString());                }                @Override                public void onFailure(Call call, Throwable t)                 {                  resultTV.setText(t.getMessage());                }    });}

以上为没有经过封装的、原生态的Retrofit写网络请求的代码。我们可以封装创建Retrofit和service部分的代码,然后Activity用创建一个Callback作为参数给Call,这样Activity中只关注请求的结果,而且Call有cancel方法可以取消一个请求,好像没Rxjava什么事了,我觉得可以写到这就下班了~

接下来我们要面对的问题是这样的如果我的Http返回数据是一个统一的格式,例如

{  "resultCode": 0,      "resultMessage": "成功",       "data": {}}

我们如何对返回结果进行一个统一的处理呢?

另外,我的ProgressDialog的show方法应该在哪调用呢?看样子只能在getMovie()这个方法里面调用了,换个地方发出请求就要在对应的Listener里面写一遍show()的代码,其实挺闹心。

而且错误请求我也想集中处理掉不要贴重复的代码。

我们先来看结合了Rxjava之后,事情有没有变化的可能。当然即便是不用Rxjava,依旧能够做很多的封装,只是比较麻烦。

如需查看项目代码 --> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step1

1.3 添加Rxjava

Retrofit本身对Rxjava提供了支持。

添加Retrofit对Rxjava的支持需要在Gradle文件中添加

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'

当然我们已经添加过了。

然后在创建Retrofit的过程中添加如下代码:

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

这样一来我们定义的service返回值就不在是一个Call了,而是一个Observable

重新定义MovieService

public interface MovieService {      @GET("top250")      Observable getTopMovie(@Query("start") int start, @Query("count") int count);}

getMovie方法改为:

//进行网络请求private void getMovie(){      String baseUrl = "https://api.douban.com/v2/movie/";      Retrofit retrofit = new Retrofit.Builder()                                  .baseUrl(baseUrl)                                  .addConverterFactory(GsonConverterFactory.create())                                  .addCallAdapterFactory(RxJavaCallAdapterFactory.create())                                  .build();      MovieService movieService = retrofit.create(MovieService.class);      movieService.getTopMovie(0, 10)    .subscribeOn(Schedulers.io())    .observeOn(AndroidSchedulers.mainThread())    .subscribe(new Subscriber()                         {                              @Override                              public void onCompleted()                               {                                Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();                              }                              @Override                              public void onError(Throwable e)                               {                                resultTV.setText(e.getMessage());                              }                              @Override                              public void onNext(MovieEntity movieEntity)                               {                                resultTV.setText(movieEntity.toString());                              }});}

这样基本上就完成了Retrofit和Rxjava的结合,但是我知道你们当然不会满意的。

接下来我们把创建Retrofit的过程封装一下,然后希望Activity创建Subscriber对象传进来。

如需查看项目代码 --> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step2

1.4 将请求过程进行封装

创建一个对象HttpMethods

public class HttpMethods {  public static final String BASE_URL = "https://api.douban.com/v2/movie/";private static final int DEFAULT_TIMEOUT = 5;private Retrofit retrofit;private MovieService movieService;//构造方法私有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();  movieService = retrofit.create(MovieService.class);}//在访问HttpMethods时创建单例private static class SingletonHolder{  private static final HttpMethods INSTANCE = new HttpMethods();}//获取单例public static HttpMethods getInstance(){  return SingletonHolder.INSTANCE;}/*** 用于获取豆瓣电影Top250的数据* @param subscriber 由调用者传过来的观察者对象* @param start 起始位置* @param count 获取长度*/public void getTopMovie(Subscriber subscriber, int start, int count){  movieService.getTopMovie(start, count)    .subscribeOn(Schedulers.io().unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(subscriber);}}

用一个单例来封装该对象,在构造方法中创建Retrofit和对应的Service。如果需要访问不同的基地址,那么你可能需要创建多个Retrofit对象,或者干脆根据不同的基地址封装不同的HttpMethod类。

我们回头再来看MainActivity中的getMovie方法:

private void getMovie(){      subscriber = new Subscriber()       {            @Override             public void onCompleted()              {                Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();             }            @Override            public void onError(Throwable e)             {              resultTV.setText(e.getMessage());            }            @Override            public void onNext(MovieEntity movieEntity)             {              resultTV.setText(movieEntity.toString());            }      };  HttpMethods.getInstance().getTopMovie(subscriber, 0, 10);} 

其中subscriber是MainActivity的成员变量。

如需查看项目代码 --> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step3

2.相同格式的Http请求数据该如何封装

第二部分和第三部分我参考了知乎上的一个问答:RxJava+Retrofit,在联网返回后如何先进行统一的判断?不过没有完整的示例,所以在这写一个完整的示例出来。

这个段落我们来聊一下有些Http服务返回一个固定格式的数据的问题。例如:

{  "resultCode": 0,      "resultMessage": "成功",      "data": {}}

大部分的Http服务可能都是这样设置,resultCode和resultMessage的内容相对比较稳定,而data的内容变化多端,72变都不一定够变的,有可能是个User对象,也有可能是个订单对象,还有可能是个订单列表。按照我们之前的用法,使用Gson转型需要我们在创建subscriber对象是指定返回值类型,如果我们对不同的返回值进行封装的话,那可能就要有上百个Entity了,看着明明是很清晰的结构,却因为data的不确定性无奈了起来。

少年,不必烦恼,来来来~ 老衲赐你宝典葵花,老衲就是练了这个才出家。。。

我们可以创建一个HttpResult类

public class HttpResult {      private int resultCode;      private String resultMessage;      private T data;}

如果data是一个User对象的话。那么在定义Service方法的返回值就可以写为

Observable>

这样一来HttpResult就相当于一个包装类,将结果包装了起来,但是在使用的时候要给出一个明确的类型。

在上面的示例中,我也创建了一个HttpResult类,用来模仿这个形式,将其中的Subject单独封装了起来。

public class HttpResult {      //用来模仿resultCode和resultMessage      private int count;      private int start;      private int total;      private String title;      //用来模仿Data      private T subjects;}

这样泛型的时候就要写为:

Observable>>

如需查看项目代码 --> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step4

3.相同格式的Http请求数据统一进行预处理

既然我们有了相同的返回格式,那么我们可能就需要在获得数据之后进行一个统一的预处理。

当接收到了一个Http请求结果之后,由于返回的结构统一为

{  "resultCode": 0,    "resultMessage": "成功",      "data": {}}

我们想要对resultCoderesultMessage先做一个判断,因为如果resultCode == 0代表success,那么resultCode != 0时data一般都是null

Activity或Fragment对resultCoderesultMessage基本没有兴趣,他们只对请求状态data数据感兴趣。

基于这种考虑,我们在resultCode != 0的时候,抛出个自定义的ApiException。这样就会进入到subscriber的onError中,我们可以在onError中处理错误信息。

另外,请求成功时,需要将data数据转换为目标数据类型传递给subscriber,因为,Activity和Fragment只想拿到和他们真正相关的数据。

使用Observable的map方法可以完成这一功能。

HttpMethods中创建一个内部类HttpResultFunc,代码如下:

/*** 用来统一处理Http的resultCode,并将HttpResult的Data部分剥离出来返回给subscriber** @param  Subscriber真正需要的数据类型,也就是Data部分的数据类型*/private class HttpResultFunc implements Func1, T>{      @Override      public T call(HttpResult httpResult)       {            if (httpResult.getResultCode() != 0)             {              throw new ApiException(httpResult.getResultCode());            }            return httpResult.getData();      }}

然后我们的getTopMovie方法改为:

public void getTopMovie(Subscriber> subscriber, int start, int count){      movieService.getTopMovie(start, count)                            .map(new HttpResultFunc>())                            .subscribeOn(Schedulers.io())                            .unsubscribeOn(Schedulers.io())                            .observeOn(AndroidSchedulers.mainThread())                            .subscribe(subscriber);}

由于HttpResult中的泛型T就是我们希望传递给subscriber的数据类型,而数据可以通过httpResult的getData方法获得,这样我们就处理了泛型问题,错误处理问题,还有将请求数据部分剥离出来给subscriber

这样我们只需要关注Data数据的类型,而不必在关心整个过程了。

需要注意一点,就是在定义Service的时候,泛型是

HttpResult//orHttpResult>

而在定义Subscriber的时候泛型是javaUser//orList

不然你会得到一个转型错误。

如需查看项目代码 --> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step5

代码中我是用豆瓣数据模拟了HttpResult中的resultCode和resultMessage,与文档中的代码略有出入。

4.如何取消一个Http请求 -- 观察者之间的对决,Observer VS Subscriber

4.1 取消一个Http请求

这一部分我们来聊一下关于取消Http请求的事情,已经Oberver和Subscriber这两个体位我们哪个更容易给我们G点。

如果没有使用Rxjava,那么Service返回的是一个Call,而这个Call对象有一个cancel方法可以用来取消Http请求。那么用了Rxjava之后,如何来取消一个请求呢?因为返回值是一个Observable。我们能做的似乎只有解除对Observable对象的订阅,其他的什么也做不了。

好在Retrofit已经帮我们考虑到了这一点。答案在RxJavaCallAdapterFactory这个类的源码中可以找到

static final class CallOnSubscribe implements Observable.OnSubscribe> {      private final Call originalCall;      CallOnSubscribe(Call originalCall)       {        this.originalCall = originalCall;      }@Override       public void call(final Subscriber super Response> subscriber)       {            // Since Call is a one-shot type, clone it for each new subscriber.            final Call call = originalCall.clone();            // Attempt to cancel the call if it is still in-flight on             unsubscription.subscriber.add(Subscriptions.create(new Action0() {                                                     @Override                                                      public void call() {                                call.cancel(); }}));            try {                Response response = call.execute();                if (!subscriber.isUnsubscribed()) {                  subscriber.onNext(response);                }            } catch (Throwable t) {                Exceptions.throwIfFatal(t);                if (!subscriber.isUnsubscribed()) {                  subscriber.onError(t);                }    return;  }            if (!subscriber.isUnsubscribed()) {              subscriber.onCompleted();            }}}

我们看到call方法中,给subscriber添加了一个Subscription对象,Subscription对象很简单,主要就是取消订阅用的,如果你查看Subscriptions.create的源码,发现是这样的

public static Subscription create(final Action0 unsubscribe) {  return BooleanSubscription.create(unsubscribe);}

利用了一个BooleanSubscription类来创建一个Subscription,如果你点进去看BooleanSubscription.create方法一切就清晰了,当接触绑定的时候,subscriber会调用Subscription的unsubscribe方法,然后触发创建Subscription时候的传递进来的Action0的call方法。RxJavaCallAdapterFactory帮我们给subscriber添加的是call.cancel(),

总结起来就是说,我们在Activity或者Fragment中创建subscriber对象,想要取消请求的时候调用subscriber的unsubscribe方法就可以了。

对不起这一节有太多的SubscriberSubscription以及ObserverObservable,老衲当时看的时候也是不知道吐了多少次了,习惯了就好了。

4.2 为什么会提到Oberver

提到Observer的过程是这样的。由于Subscriber一旦调用了unsubscribe方法之后,就没有用了。且当事件传递到onError或者onCompleted之后,也会自动的解绑。这样出现的一个问题就是每次发送请求都要创建新的Subscriber对象。

这样我们就把注意力放到了Observer,Observer本身是一个接口,他的特性是不管你怎么用,都不会解绑,为什么呢?因为他没有解绑的方法。所以就达到了复用的效果,一开始我一直美滋滋的用Observer。事实上,如果你用的是Observer,在调用Observable对象的subscribe方法的时候,会自动的将Observer对象转换成Subscriber对象。

下面是源码:

public final Subscription subscribe(final Observer super T> observer) {  if (observer instanceof Subscriber)   {    return subscribe((Subscriber super T>)observer);  }  return subscribe(new Subscriber(){                   @Overridepublic void onCompleted() {observer.onCompleted();}@Overridepublic void onError(Throwable e) {observer.onError(e);}@Overridepublic void onNext(T t) {observer.onNext(t);}});}

后来发现了问题,

问题1 无法取消,因为Observer没有unsubscribe方法问题2 没有onStart方法 这个一会聊

这两个问题是很痛苦的。所以,为了后面更好的高潮,我们还是选择用Subscriber。

5.一个需要ProgressDialog的Subscriber该有的样子

我们希望有一个Subscriber在我们每次发送请求的时候能够弹出一个ProgressDialog,然后在请求接受的时候让这个ProgressDialog消失,同时在我们取消这个ProgressDialog的同时能够取消当前的请求,而我们只需要处理里面的数据就可以了。

我们先来创建一个类,就叫ProgressSubscriber,让他继承Subscriber

Subscriber给我们提供了onStart、onNext、onError、onCompleted四个方法。

其中只有onNext方法返回了数据,那我们自然希望能够在onNext里面处理数据相关的逻辑。

onStart方法我们用来启动一个ProgressDialog。onError方法我们集中处理错误,同时也停止ProgressDialogonComplated方法里面停止ProgressDialog

其中我们需要解决两个问题

问题1 onNext的处理问题2 cancel掉一个ProgressDialog的时候取消请求

我们先来解决问题1

5.1处理onNext

我们希望这里能够让Activity或者Fragment自己处理onNext之后的逻辑,很自然的我们想到了用接口。问题还是泛型的问题,这里面我们必须指定明确的类型。所以接口还是需要泛型。

我们先来定义一个接口,命名SubscriberOnNextListener

public interface SubscriberOnNextListener {  void onNext(T t);}

代码很简单。再来看一下ProgressSubscriber现在的代码

public class ProgressSubscriber extends Subscriber {      private SubscriberOnNextListener mSubscriberOnNextListener;      private Context context;      public ProgressSubscriber(SubscriberOnNextListener mSubscriberOnNextListener, Context context)       {        this.mSubscriberOnNextListener = mSubscriberOnNextListener;        this.context = context;      }      @Override      public void onStart() {}      @Override      public void onCompleted()       {        Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();      }      @Override      public void onError(Throwable e)       {        Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show();      }      @Override      public void onNext(T t)       {        mSubscriberOnNextListener.onNext(t);      }}

我知道传Context不好,不过为了演示而已,大家可以自己封装一下Toast。

MainActivity使用是这样的:

先来定义一个SubscriberOnNextListener对象,可以在onCreate里面创建这个对象

private SubscriberOnNextListener getTopMovieOnNext;@Overrideprotected void onCreate(Bundle savedInstanceState) {      super.onCreate(savedInstanceState);      setContentView(R.layout.activity_main);      ButterKnife.bind(this);      getTopMovieOnNext = new SubscriberOnNextListener>()       {            @Override            public void onNext(List subjects)             {              resultTV.setText(subjects.toString());            }      };}

getMovie方法这么写:

private void getMovie(){  HttpMethods.getInstance().getTopMovie(new ProgressSubscriber(getTopMovieOnNext, MainActivity.this), 0, 10);}

这样Activity或Fragment就只需要关注拿到结果之后的逻辑了,其他的完全不用操心。

如需查看项目代码 --> 代码地址:

https://github.com/tough1985/RxjavaRetrofitDemo

选择Tag -> step6

5.2处理ProgressDialog

我们希望当cancel掉ProgressDialog的时候,能够取消订阅,也就取消了当前的Http请求。所以我们先来创建个接口来处理这件事情。

public interface ProgressCancelListener {  void onCancelProgress();}

然后我们用ProgressSubscriber来实现这个接口,这样ProgressSubscriber就有了一个onCancelProgress方法,在这里面取消订阅。

@Overridepublic void onCancelProgress() {  if (!this.isUnsubscribed())   {    this.unsubscribe()    ;}}

然后我用了一个Handler来封装了ProgressDialog。

public class ProgressDialogHandler extends Handler {  public static final int SHOW_PROGRESS_DIALOG = 1;public static final int DISMISS_PROGRESS_DIALOG = 2;private ProgressDialog pd;private Context context;private boolean cancelable;private ProgressCancelListener mProgressCancelListener;public ProgressDialogHandler(Context context, ProgressCancelListener mProgressCancelListener,boolean cancelable) {  super();  this.context = context;  this.mProgressCancelListener = mProgressCancelListener;  this.cancelable = cancelable;}private void initProgressDialog(){  if (pd == null)   {    pd = new ProgressDialog(context);    pd.setCancelable(cancelable);    if (cancelable)     {      pd.setOnCancelListener(new DialogInterface.OnCancelListener()                              {@Overridepublic void onCancel(DialogInterface dialogInterface) {mProgressCancelListener.onCancelProgress();}});}if (!pd.isShowing()) {pd.show();}}}private void dismissProgressDialog(){if (pd != null) {pd.dismiss();pd = null;}}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case SHOW_PROGRESS_DIALOG:initProgressDialog();break;case DISMISS_PROGRESS_DIALOG:dismissProgressDialog();break;}}}

Handler接收两个消息来控制显示Dialog还是关闭Dialog。创建Handler的时候我们需要传入ProgressCancelListener的对象实例。

最后贴出ProgressSubscriber的完整代码:

public class ProgressSubscriber extends Subscriber implements ProgressCancelListener{      private SubscriberOnNextListener mSubscriberOnNextListener;      private ProgressDialogHandler mProgressDialogHandler;      private Context context;      public ProgressSubscriber(SubscriberOnNextListener mSubscriberOnNextListener, Context context)       {            this.mSubscriberOnNextListener = mSubscriberOnNextListener;            this.context = context;            mProgressDialogHandler = new ProgressDialogHandler(context, this, true);  }      private void showProgressDialog()      {            if (mProgressDialogHandler != null)             {              mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();            }      }      private void dismissProgressDialog()      {            if (mProgressDialogHandler != null)             {                  mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget();                  mProgressDialogHandler = null;            }      }      @Override      public void onStart()       {        showProgressDialog();      }      @Override      public void onCompleted()       {            dismissProgressDialog();            Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();      }      @Override      public void onError(Throwable e)       {            dismissProgressDialog();            Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show();      }      @Override      public void onNext(T t)       {        mSubscriberOnNextListener.onNext(t);      }      @Override      public void onCancelProgress()       {            if (!this.isUnsubscribed())             {              this.unsubscribe();            }      }}

目前为止,就封装完毕了。以上是我在用Rxjava和Retrofit过程中踩过的一些坑,最后整合出来的,由于没有在实际的项目中跑过,有问题的话希望能够提出来大家讨论一下,拍砖也欢迎。

现在我们再写一个新的网络请求,步骤是这样的:1. 在Service中定义一个新的方法。2. 在HttpMethods封装对应的请求(代码基本可以copy)3. 创建一个SubscriberOnNextListener处理请求数据并刷新UI。

最后

如果你觉得写更改线程的代码觉得也很烦的话,可以把订阅这部分也封装起来:

public void getTopMovie(Subscriber> subscriber, int start, int count){  //原来的样子  // movieService.getTopMovie(start, count)  // .map(new HttpResultFunc>())  // .subscribeOn(Schedulers.io())  // .unsubscribeOn(Schedulers.io())  // .observeOn(AndroidSchedulers.mainThread())  // .subscribe(subscriber);    //修改之后的样子  Observable observable = movieService.getTopMovie(start, count)    .map(new HttpResultFunc>())toSubscribe(observable, subscriber);}//添加线程管理并订阅private void toSubscribe(Observable o, Subscriber s){o.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(s);}

让你每次写一个请求的时候,写的代码尽量少,更多的精力放在业务逻辑本身。

最后的最后

如果你的httpResult格式本身没有问题,但是data中的内容是这样的:

{      "resultCode": 0,      "resultMessage": "成功",      "data":       {        "user": {},           "orderArray": []      }}

这样的情况还能不能继续使用这样的框架呢?我的解决方法是封装一个类,把user和orderArray作为类的属性。但是如果你的服务器一会data本身是一个完整的user数据,一会又是这样:"data": {"user": {}, "orderArray": []}那我觉得你有必要跟你的服务端好好聊聊了,请他吃顿饭和顿酒,大不了献出菊花就是了。

但是如果服务已经上线了!!!

对不起,骚年......

老衲会在你坟前念300遍Thinking in java替你超度的~

希望你用Retrofit和Rxjava的新体位能够享受到新的高潮。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/536981.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis源码阅读(二):动态节点解析2.1 —— SqlSource和SqlNode

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

k8s边缘节点_边缘计算,如何啃下集群管理这块硬骨头?

导读边缘计算平台&#xff0c;旨在将边缘端靠近数据源的计算单元纳入到中心云&#xff0c;实现集中管理&#xff0c;将云服务部署其上&#xff0c;及时响应终端请求。然而&#xff0c;成千上万的边缘节点散布于各地&#xff0c;例如银行网点、车载节点等&#xff0c;节点数量甚…

Mybatis源码阅读(二):动态节点解析2.2 —— SqlSourceBuilder与三种SqlSource

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

搞懂toString()与valueOf()的区别

一、toString&#xff08;&#xff09; 作用&#xff1a;toString&#xff08;&#xff09;方法返回一个表示改对象的字符串&#xff0c;如果是对象会返回&#xff0c;toString() 返回 “[object type]”,其中type是对象类型。 二、valueOf( ) 作用&#xff1a;valueOf房啊发返…

oracle入库的速度能到多少_倒车入库别练复杂了,其实就这两点

教练总会让学员反复练倒车入库&#xff0c;但不少学员都会有这样的疑惑&#xff1a;为什么每一次倒库结果都不一样&#xff0c;倒车入库的练习重点是什么&#xff1f;倒车入库是科二的重点及难点&#xff0c;但只要掌握以下两个关键&#xff0c;顺利通过真不难&#xff1a;01方…

Mybatis源码阅读(三):结果集映射3.1 —— ResultSetBuilder与简单映射

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

kdj买卖指标公式源码_通达信指标公式源码MACD背离KDJ背离指标

N1:5;N2:10;N3:21;N4:60;牛熊:EMA(CLOSE,N4),COLORGREEN,LINETHICK3;DIFF:EMA(CLOSE,12) - EMA(CLOSE,26);DEA:EMA(DIFF,8);A1:BARSLAST(REF(CROSS(DIFF,DEA),1)); B1:REF(C,A11)>C AND REF(DIFF,A11)DRAWTEXT(IF(B1>0,1,0),L-0.1,MACD底背),COLORGREEN;RSV:(CLOSE-LLV(L…

Mybatis源码阅读(三):结果集映射3.2 —— 嵌套映射

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

gridview获取选中行数据_Word转Excel,不想熬夜加班,那就掌握这个数据清洗方法...

私信回复关键词【福利】~获取丰富办公资源&#xff0c;助你高效办公早下班&#xff01;小伙伴们&#xff0c;大家好&#xff0c;我是专治各种疑难杂「数」的农夫~今天&#xff0c;我就为大家介绍一种高效的数据清洗方法&#xff0c;助你告别熬夜加班&#xff0c;拥抱美好的夜晚…

Mybatis源码阅读(三):结果集映射3.3 —— 主键生成策略

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

list最大容量_Java 基础(四)集合源码解析 List

List 接口前面我们学习了Iterator、Collection&#xff0c;为集合的学习打下了基础&#xff0c;现在我们来学习集合的第一大体系 List。List 是一个接口&#xff0c;定义了一组元素是有序的、可重复的集合。List 继承自 Collection&#xff0c;较之 Collection&#xff0c;List…

Mybatis源码阅读(四):核心接口4.1——StatementHandler

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

Shell学习之结合正则表达式与通配符的使用(五)

Shell学习之结合正则表达式与通配符的使用 目录 通配符 正则表达式与通配符通配符通配符的使用正则表达式 正则表达式正则表达式的使用通配符 正则表达式与通配符 正则表达式用来在文件中匹配符合条件的字符串&#xff0c;正则是包含匹配。grep、awk、sed等命令可以支持正则表达…

Mybatis源码阅读(四):核心接口4.2——Executor(上)

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

接收xml参数_SpringBoot实战(二):接收xml请求

强烈推荐一个大神的人工智能的教程&#xff1a;http://www.captainbed.net/zhanghan【前言】最近在对接一个第三方系统&#xff0c;需要接收第三方系统的回调&#xff0c;而且格式为XML形式&#xff0c;之前自己一般接收的参数是Json形式&#xff0c;于是乎做个实验验证一下使用…

报错 插入更新_window如何解决mysql数据量过大导致的报错

window如何解决报错“The total number of locks exceeds the lock table size”第一大步&#xff0c;查看mysql配置信息在CMD中输入mysql -hlocalhost -uroot -p #如果设置了密码直接接在p 后面 show variables like %storage_engine%以下为结果可以看到InnoDB是MySQL的默认引…

Mybatis源码阅读(四):核心接口4.2——Executor(下)

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

Mybatis源码阅读(五 ):接口层——SqlSession

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

插入公式_一个小工具,彻底帮你搞定在Markdown中插入公式的问题

在编辑Markdown文档时&#xff0c;插入公式是一个挺麻烦的活儿。需要掌握LaTex语法。我自己看完语法后&#xff0c;直接放弃&#xff0c;这绝对是反人类的语法。&#xff08;好吧&#xff0c;是我不会用...&#xff09;但是&#xff0c;我相信你看了这篇文章后&#xff0c;绝对…

Mybatis源码阅读(一):Mybatis初始化1.2 —— 解析别名、插件、对象工厂、反射工具箱、环境

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…