在 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();
}
关于 map
和 flatMap
之间的区别 - 确实没有适用于所有情况的简单答案。一般来说,我是这样处理的:
我使用 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" 项的类型。我希望这很清楚,如果有点冗长。
回到 map
与 flatMap
的最后一部分 - 您可以使用任何一个。 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;
}
}
这是我的代码
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();
}
关于 map
和 flatMap
之间的区别 - 确实没有适用于所有情况的简单答案。一般来说,我是这样处理的:
我使用 map
进行所有简单的一对一转换:链中的每个 X 都应转换为一个 Y。
一些例子:
- 将一个
String
转为另一个String
大写 - 通过计算总和 将
- 通过找到最大值将
List<Double>
转换为Double
如您所见,X 和 Y 可以是任何类型(事实上,一个或两个可以是复杂的数据类型,如Collection
)——但是,对于每个输入实体,您仍然会得到一个输出实体。
Pair<Integer, Integer>
转换为Integer
我使用 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" 项的类型。我希望这很清楚,如果有点冗长。
回到 map
与 flatMap
的最后一部分 - 您可以使用任何一个。 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;
}
}