首页 > 解决方案 > 当我需要前一个服务的结果时,如何使用 RxJava 链接多个改造服务?

问题描述

.

它的目的是检索库存的详细信息。我有 2 项服务,一项用于获取可用库存,另一项为您提供给定库存的详细信息。

先看看我的改造界面

public interface RetrofitApiService {

    @GET("inv.svc/availableInventories")
    Single<AvailableInventories> getAvailableInventories();

    @GET("inv.svc/inventoryDetails")
    Single<InventoryDetails> getInventoryDetails(@Query("invName") String invName);
}

这些是改造服务构建的对象:

AvailableInventories
    List<InventoryName> inventoryNames

InventoryName
    String id
    String name
    String ref

InventoryDetails
    List<InventoryLine> inventoryLines

InventoryLine
    String articleRef
    String inventoryRef
    String conditioning
    String CountedStock
    String expectedStock

所以我要调用getAvailableInventories()它将返回一个AvailableInventories包含 3 的对象InventoryName(例如)首先我想将它们存储inventoryNames在 my_database.Inventory_names

InventoryName
    String "1"
    String "paris-warehouse"
    String "az2r8"

InventoryName
    String "2"
    String "mila-warehouse"
    String "d8f5s"

InventoryName
    String "3"
    String "berlin-warehouse"
    String "g8z3d"

那么我将不得不打电话

getInventoryDetails("az2r8")
    store in database, table inventory_line_details
getInventoryDetails("d8f5s")
    store in database, table inventory_line_details
getInventoryDetails("g8z3d")
    store in database, inventory_line_details

最后我需要重定向到另一个屏幕。

我怎样才能在 RxJava 中做到这一点?以前我会使用简单的 android asynctasks 并使它们非异步使用.execute.get()

但是似乎我不能用 rx java 做到这一点。

我将不得不调用第一个服务,然后使用类似的东西.iterate或为每个结果.forEach调用我的服务getInventoryDetails

我很迷茫。

我没有办法做这样的事情吗?:

compositeDisposable.add(simpleRetrofitService.getAvailableInventories()
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.io())
    .subscribe(this::storeNamesToDatabse, this::logErrorAndDisplayPopup)); <-make it blocking and store AvailableInventories somewhere

for (InventoryName inventoryName : availableInventories) {
    compositeDisposable.add(simpleRetrofitService.getInventoryDetails()
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.io())
        .subscribe(this::storeDetailsToDatabse, this::logErrorAndDisplayPopup)); <-make it blocking and store InventoryDetails somewhere
}

goToNextScreen()

谢谢。

Ps:正如你所看到的 java 8,streams 和 lambda 对我来说是新的

标签: androidasynchronousretrofit2rx-java2

解决方案


在您的情况下,您可以使用flatMapzip运算符,如下所示:

compositeDisposable.add(simpleRetrofitService.getAvailableInventories()
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.io())
    .doOnSuccess(this::storeNamesToDatabse) // store names on success
    .flatMap(this::getInventoryDetails) // once availableInventories is fetched, proceed to get details 
    .subscribe(inventoryDetailsList -> { // we get a list of inventoryDetails
        this.storeDetailsToDatabse(inventoryDetailsList); // modify your function to use list of inventory details instead
        goToNextScreen(); // go to next screen when network calls finished
    }, this::logErrorAndDisplayPopup))
}

WheregetInventoryDetails(...)返回另一个Single向下游发射:

Single<List<InventoryDetails>> getInventoryDetails(AvailableInventories availableInventories) {
    List<Single<InventoryDetails>> singles = new ArrayList<>();
    for (InventoryName inventoryName : availableInventories) {
       singles.add(
           simpleRetrofitService.getInventoryDetails(inventoryName)
             .subscribeOn(Schedulers.io())
             .observeOn(Schedulers.io()
       );
    }
    return Single.zip(singles, inventoryDetailsList -> (List<InventoryDetails>) inventoryDetailsList); // here you might need to cast the result
}

此外,goToNextScreen()在订阅回调中移动您的呼叫,以确保在您离开屏幕之前一切都完成(如上所示)。


推荐阅读