在 retrofit 和 rxjava 完成后调用一个函数

Call a function after retrofit and rxjava completes

这是我的代码

final ApiInterface apiInterface=restAdapter.create(ApiInterface.class);
apiInterface.submitDataToAnalyze("dataToAnalyze","852741963",1,"123","lalala","2015-11-20")
   .flatMap(new Func1<BasicResponse, Observable<?>>() {
    @Override
    public Observable<?> call(BasicResponse basicResponse) {
        if (basicResponse.getResult() == 1){
           return apiInterface.getSuggestion("dataToAnalyze","852741963",1,"123","lalala","2015-11-20");
         }else{
            return null; //error
         }
  }
}).flatMap(new Func1<Observable<?>, Integer>() {
    @Override
    public Integer call(Observable<?> input) {
        if (input == null){
            //update a table
            return 0;
        }else{
            //update another table using data retrieved from apiInterface.getSuggestion
           return 1;
        }
    }
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());

我应该怎么做,以便在通话完成时,在

return apiInterface.getSuggestion()

return Observable.just(null)

会调用两个不同的函数(每种情况一个)?当然,函数需要处理调用返回的数据。

顺便说一句,第二个 flatMap returns 这个错误:

'flatMap(rx.functions.Func1<? super java.lang.Object,? extends rx.Observable<?>>)' in 'rx.Observable' cannot be applied to '(anonymous rx.functions.Func1<rx.Observable<?>,java.lang.Integer>)'

如果有帮助,这是我的 submitDataToAnalyze 和 getSuggestion 界面

@POST("/request.php")
Observable<BasicResponse> submitDataToAnalyze(@Query("action") String action, @Query("auth") String auth, @Query("ver") int ver, @Query("uuid") String uuid, @Query("dataToAnalyze") String dataToAnalyze,
                              @Query("requestForDate") String requestForDate);

@POST("/request.php")
Observable<BasicResponse> getSuggestion(@Query("action") String action, @Query("auth") String auth, @Query("ver") int ver, @Query("uuid") String uuid, @Query("dataToAnalyze") String dataToAnalyze,
                             @Query("requestForDate") String requestForDate);

flatMap 应该 return 是一个可观察的,所以 return null 应该是 return Observable.just(null)。当您将其他运算符链接到 flatmap.

时,直接返回 null 将导致 NPE

之后您可以链接下一个操作。使用什么运算符实际上取决于您希望该函数执行的操作。

两条建议:

使用filter:

apiInterface.submitDataToAnalyze(...)
  .filter(br -> br.getResult() == 1)
  .flatMap(new Func1<BasicResponse, Observable<?>>() {
    @Override
    public Observable<?> call(BasicResponse basicResponse) {
       return apiInterface.getSuggestion(...);
    }
  })
...

或 return Observable.empty()flatMap:

if (basicResponse.getResult() == 1){
    return apiInterface.getSuggestion(...);
}else{
    return Observable.empty();
}

关于 mapflatMap 之间的区别 - 确实没有适用于所有情况的简单答案。一般来说,我是这样处理的:

我使用 map 进行所有简单的一对一转换:链中的每个 X 都应转换为一个 Y。

一些例子:

  • 将一个String转为另一个String大写
  • 通过计算总和
  • Pair<Integer, Integer>转换为Integer
  • 通过找到最大值将 List<Double> 转换为 Double 如您所见,X 和 Y 可以是任何类型(事实上,一个或两个可以是复杂的数据类型,如 Collection)——但是,对于每个输入实体,您仍然会得到一个输出实体。

我使用 flatMap 用于至少满足以下条件之一的情况:

  • 转换本质上是异步的,例如网络请求
  • 转换不一定为每个输入产生一个输出,例如它可以为每个输入产生一个或多个输出
  • 转换有一些明显的错误或类似错误的情况,应该在那里解决,而不是沿着链传播 - 我认为你的例子属于这种情况(以及异步网络调用)。

如果这三个条件听起来很熟悉,那是因为 Erik Meijer 在他的演讲中列出了它们:https://www.youtube.com/watch?v=sTSQlYX5DU0

关于更新代码中的编译错误 - 正确的类型声明应如下所示:

apiInterface.submitDataToAnalyze("dataToAnalyze","852741963",1,"123","lalala","2015-11-20")
.flatMap(new Func1<BasicResponse, Observable<BasicResponse>>() {
    @Override
    public Observable<BasicResponse> call(BasicResponse basicResponse) {
        if (basicResponse.getResult() == 1){
            return apiInterface.getSuggestion("dataToAnalyze","852741963",1,"123","lalala","2015-11-20");
        } else {
            return Observable.just(null);
        }
    }
})
.flatMap(new Func1<BasicResponse, Observable<Integer>>() {
    @Override
    public Observable<Integer> call(BasicResponse input) {
        if (input == null){
            //update a table
            return Observable.just(0);
        } else {
            //update another table using data retrieved from apiInterface.getSuggestion
           return Observable.just(1);
        }
    }

因为 getSuggestion returns 一个 Observable<BasicResponse> 必须是第一个 Func1 的 return 类型 - 即使实际值 returned 必须是 null.

我想你的误会在于下面的内容,我们来看看吧。然后 RxJava 不会将 Observable<BasicResponse> 传递到链下 - 因为您正在使用 flatMap 它将在内部订阅您创建的 Observable<BasicResponse> 然后将 Observable 发出的每个项目并向下传递 that。这也是为什么下一个 Func1 必须是 Func1<BasicResponse, Observable<Integer>> 而不是 Func1<Observable<BasicResponse>, Observable<Integer>>。等待链下的任何函数的输入类型必须是 BasicReponse,因为这是来自 Observable<BasicResponse> 的 "unpacked" 项的类型。我希望这很清楚,如果有点冗长。

回到 mapflatMap 的最后一部分 - 您可以使用任何一个。 flatMap 如果您正确使用它,它总是有效的。但是 map 通常可以更短(并且可能更有效一些,因为它不会创建更多的内部 Observables)。一般来说,如果你有一个 flatMap 并且在每个分支中你只有 return 一个 Observable.just() 你也可以使用一个简单的地图。因此,您可以将代码重写为:

.map(new Func1<BasicResponse, Integer>() {
    @Override
    public Integer call(BasicResponse input) {
        if (input == null){
            //update a table
            return 0;
        } else {
            //update another table using data retrieved from apiInterface.getSuggestion
           return 1;
        }
    }