使用 Observable.from 和 flatMap 对 List 中的每个项目执行操作并将结果设置在每个列表元素中

Using Observable.from and flatMap to perform operation on each item in an List and to set the result in each list element

我得到一个搜索项列表。此列表中的每个元素都存在一个纬度和经度。对于这些坐标,我使用采用这两个值的 googleService 和 returns 具有此位置名称(城市名称)的 JsonObject。这很好用!在我的 onNext 中,我可以在我的日志输出中看到城市。

现在我的问题是:我想将此名称存储在相应的列表元素中。喜欢: item.setLocation(loc) -> 但我无法在 onNext() 中设置对项目的访问!我怎样才能访问项目??

 Observable.from(searchItems)
            .flatMap(item -> googleService.getCityNameFromLatLngObserable(item.getLat(), item.getLng(), null)
            .subscribeOn(Schedulers.io()))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<JsonObject>() {
                @Override
                public void onCompleted() {
                    view.updateSearches(searchItem);
                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onNext(JsonObject response) {
                    if (response.get("results").getAsJsonArray().size() > 0) {
                        String loc = response.get("results").getAsJsonArray()
                                .get(0).getAsJsonObject().get("address_components").getAsJsonArray()
                                .get(2).getAsJsonObject().get("long_name").toString();
                        Log.d("CONAN", "City: "+loc);

                        item.setLocation(loc); //does not work
                    }
                }
            });

实际上你不应该真的改变你的 searchItems 而是用新信息创建新的。这是为了加强不可变性,这对 Rx 来说非常重要。

有不止一种方法可以做到这一点,但这里有一种可能的方法。您需要该项目来调用您的 Google 服务,因此您不能使用 zip 或其任何朋友。因此,让我们像您拥有的那样保留第一位,并获得发出每个搜索项的可观察对象:

Observable.from(searchItems)

现在让我们继续创建新的搜索项及其位置。

Observable.from(searchItems)
          .flatMap(item -> googleService
                              .getCityNameFromLatLngObserable(
                                    item.getLat(),
                                    item.getLng(), null)
                              .map(jsonObject -> /* create a 
                                                    new item with location */))
          .subscribeOn(Schedulers.io()))
          .observeOn(AndroidSchedulers.mainThread())
          .subscribe(new Subscriber<JsonObject>() {
            @Override
            public void onCompleted() {
                view.updateSearches(searchItem);
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Item item) {
                   // Your items with location
            }
        });

我所做的是将 googleService. getCityNameFromLatLngObserable 的结果映射到具有结果位置的项目。请注意,在这里您如何通过 google?

访问项目和 json 对象 return

现在在 map 函数中,您可以使用诸如 createWithLocation(item, getLocation(jsonObject)) 之类的函数,也可以使用诸如构建器模式之类的函数:

item.toBuilder()
    .location(getLocation(jsonObject))
    .build();

另请注意,在订阅者 onNext 上,您现在有一个 Item 而不是 JsonObject 并且位置已填充。我假设你可以编码 getLocation 因为你的例子已经有了这个。

最后一件事,您也可以在项目实例中调用 setter 而不是创建新的。我建议不要这样做,因为您会给电话添加其他人可能不会想到的副作用。它通常是错误的来源。但是,您仍然可以这样做:)

希望对您有所帮助