【问题标题】:Chaining two web service calls using RxJava and Retrofit使用 RxJava 和 Retrofit 链接两个 Web 服务调用
【发布时间】:2015-11-16 13:40:09
【问题描述】:

我正在使用 RxJava 和 Retrofit。我的基本要求是,我想链接两个 api 调用,它们将一个接一个地被调用。在调用第二个 api 时,从第一个 api 收到的响应用作输入。在互联网上阅读了一些东西后,我曾经使用平面图来实现这一点。在执行此操作时,我正在显示加载程序。有时它运行平稳,但在某些情况下,此加载程序冻结。 DDMS 显示“跳过 300 帧,应用程序可能在其主线程上做太多工作”的日志。我怀疑我的一个网络调用正在主线程上运行。我无法弄清楚如何链接这两个调用,以便可以在后台顺利调用它们而不妨碍我的主线程。任何帮助是极大的赞赏 。提前致谢 这是我迄今为止尝试过的

private CompositeSubscription mSubscriptions = new CompositeSubscription();

Subscription subscription = Observable.just(getAddress())
          .subscribeOn(Schedulers.newThread())
          .flatMap(address -> mPlatformApi.secondWebService(address.getLatitude(),address.getLongitude())
          .observeOn(AndroidSchedulers.mainThread())
          .subscribe(modelTwo ->
          {
            //updating My ui
          }, throwable -> {

            //Error Handling
          });

mSubscriptions.add(subscription);


private android.location.Address getAddress(){
    String addressString = "";//some Address String
    Geocoder coder = new Geocoder(getActivity());
    android.location.Address address=null;
    try {
      ArrayList<android.location.Address> addressList = (ArrayList<android.location.Address>) coder.getFromLocationName(addressString, 1);
      if(addressList !=null && addressList.size()>0) {
        address = addressList.get(0);
      } else {

      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    return address;
  }

//My Retrofit call
Observable<modelTwo> secondWebService(@Path("lat") double lat,@Path("lon") double lon);

【问题讨论】:

  • 看起来你并没有在主线程之外做任何事情。我会将第一个网络调用的结果平面映射到第二个的参数中,然后在您的订阅方法中进行网络调用。 .subscribe() 方法中的代码是在主线程之外执行的代码。
  • getLatLonFromAddress 是否甚至在任何地方的代码中都使用过? doNetwokOperation 在做什么,它是如何定义的?另外,您使用的是哪个版本的改造?从 2.0-beta2 开始,RxJava 风格的 Retrofit 调用不再自动在另一个线程上运行。
  • @david.mihola 我已经编辑了上面的代码。我所说的网络操作只是调用方法'getAddress()'。我正在使用改造 1.9。
  • 好的,谢谢!不过,这个例子肯定有问题:getAddress 没有返回Observable,但是你在上面调用subscribeOn...这甚至不应该编译...
  • @david.mihola 我正在使用 Observable.just(getAddress())。我将再次编辑代码。真的很抱歉给您带来不便

标签: android retrofit rx-java


【解决方案1】:

考虑一下:

final android.location.Address address = getAddress();
Subscription subscription = Observable.just(address) ...

这等同于您的代码,但也应该明确指出,getAddress() 在 RxJava 参与并有机会干预之前就已评估。换句话说,当您使用just 时,subscribeOn 只能将地址的发射(在您的Subscriber 上调用onNext(address))移动到另一个线程。但是,地址的创建 - 即您的getAddress - 将在您到达这一点时已经在主线程上发生。

将getAddress 实际移动到另一个线程的最简单方法是使用defer:

Subscription subscription = Observable.defer(new
          Func0<Observable<android.location.Address>>() {

              @Override
              public Observable<android.location.Address> call() {
                  return Observable.just(getAddress());
              }
          })
          .subscribeOn(Schedulers.newThread())
          .flatMap(address -> mPlatformApi.secondWebService(address.getLatitude(),address.getLongitude()    )
          .observeOn(AndroidSchedulers.mainThread())
          .subscribe(modelTwo ->
          {
            //updating My ui
          }, throwable -> {
            //Error Handling
          });

这样,整个Func0 将在newThread() 上执行——不仅是just,还有getAddress。

【讨论】:

  • 很好的答案。我知道 Observable.just() 在主线程上运行。但我不知道这个 Observable.defer()。这绝对解决了这个用例
  • 我还有一个用例要与您讨论。在这里,我将 getAddress() 的平面映射响应映射到第二次改造调用。但假设我想链接两个改造调用。即将第一次改造调用的结果平面映射到第二次。在这种情况下,我也应该使用 Observabe.defer() 吗?
  • 不,在这种情况下,您可以只使用 Retrofit 返回的 Observable。在 2.0-beta2 之前,它已经在主线程之外运行,您可以将 flatMap 放在它后面。从 2.0-beta2 开始,默认情况下它将在您创建它的线程上运行 - 但它的构造方式是调用 subscribeOn 将移动实际的网络通信(可能还有任何 JSON 解析等)到另一个线程。
猜你喜欢
  • 2017-04-22
  • 2018-06-16
  • 1970-01-01
  • 1970-01-01
  • 2016-10-28
  • 2017-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多