【问题标题】:RxJava for each item in a list make api request with Retrofit in AndroidRxJava 为列表中的每个项目在 Android 中使用 Retrofit 发出 api 请求
【发布时间】:2017-07-17 08:46:48
【问题描述】:

我的 Android 项目中有以下问题:

我有一个使用 Retrofit 从先前的网络调用中获得的元素列表 (ArrayList)。 CategoryItem 如下所示:

public class CategoryItem {
   String id;
   String name;
   public CategoryItem(String id, String name) {
     this.id = id;
     this.name = name;
   }
   public String getId() {
     return id;
   }
   public String getName() {
     return name;
   }
}

实际上,这些类别由 20 个元素组成。现在我需要制作一个网络 API 并获取每个类别的产品列表。为此,产品 API 将类别中的 id 作为查询参数。在获得某个类别的产品列表后,我将其添加到内部 SQLite DB 中。

我想用 RxJava(1 和 2)来做这个。

到目前为止,我所做的不是多线程的,而是在 MainThread 上,这是不正确的。 我将在这里添加代码sn-p:

for (int i = 0; i < categoryItems.size(); i++) {
    CategoryItem categoryItem = categoryItems.get(i);
    final String iCat = categoryItem.getId();
    Observable<ProductResponse> call = networkManager.getApiServiceProductsRx().getProductsRx(iCat);

    Subscription subscription = call
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<ProductResponse>() {
                @Override
                public void onCompleted() {
                }

                @Override
                public void onError(Throwable e) {
                    if (e instanceof HttpException) {
                        HttpException response = (HttpException) e;
                        int code = response.code();
                        Log.d("RetrofitTest", "Error code: " + code);
                    }
                }

                @Override
                public void onNext(ProductResponse response) {
                    mProductItemsBelongingToACategory = new ArrayList<>();
                    mProductItemsBelongingToACategory = response.getProductChannel().getProductItems();
                    mDatabaseHandler.addProducts(iCat, mProductItemsBelongingToACategory);
                }
            });

    subscriptions2.add(subscription);

}

我想用 flatMap 或 flatMapIterable 来做这件事,并最终使用多线程。

【问题讨论】:

    标签: android rx-java retrofit2 rx-java2


    【解决方案1】:

    RxJava 相当于 for 循环:

    Observable.from(...) //RxJava1
    

    Observable.fromIterable(...) //RxJava2
    

    应用它可以让您遍历CategoryItem 列表。 然后每个categoryItem.getId() 必须与getProductsRx() API 调用的结果配对。然后使用toList() 将所有结果合并到单个列表中,如下所示:

    RxJava1:

    Observable.from(categoryItems)
        .flatMap(new Func1<CategoryItem, Observable<Pair<String, ProductResponse>>>() {
            @Override
            public Observable<Pair<String, ProductResponse>> call(@NonNull CategoryItem categoryItem) throws Exception {
                return Observable.zip(
                        Observable.just(categoryItem. getId()),
                        networkManager.getApiServiceProductsRx().getProductsRx(categoryItem. getId()),
                        new Func2<String, ProductResponse, Pair<String, ProductResponse>>() {
                            @Override
                            public Pair<String, ProductResponse> call(@NonNull String id, ProductResponse productResponse) throws Exception {
                                return new Pair<String, ProductResponse>(id, productResponse);
                            }
                        });
            }
        })
       .toList()
       .subscribeOn(Schedulers.io())
       .observeOn(AndroidSchedulers.mainThread())
    

    RxJava2:

    Observable.fromIterable(categoryItems)
        .flatMap(new Function<CategoryItem, ObservableSource<Pair<String, ProductResponse>>>() {
            @Override
            public ObservableSource<Pair<String, ProductResponse>> apply(@NonNull CategoryItem categoryItem) throws Exception {
                return Observable.zip(
                        Observable.just(categoryItem. getId()),
                        networkManager.getApiServiceProductsRx().getProductsRx(categoryItem. getId()),
                        new BiFunction<String, ProductResponse, Pair<String, ProductResponse>>() {
                            @Override
                            public Pair<String, ProductResponse> apply(@NonNull String id, @NonNull ProductResponse productResponse) throws Exception {
                                return new Pair<String, ProductResponse>(id, productResponse);
                            }
                        });
            }
        })
       .toList()
       .subscribeOn(Schedulers.io())
       .observeOn(AndroidSchedulers.mainThread())
    

    用 RxJava2 编写。

    以上仅为Observables。您仍然可以使用Subscriber 并将数据保存到onNext() 的数据库中。但是,您也可以在toList() 之后使用doOnNext() 运算符将数据保存到数据库中。

    【讨论】:

    • 两个问题:a) 你能在 RxJava 1 中也举一个例子吗? b)我可以在哪里保存到数据库? (请检查问题,因为我有将其保存到数据库的部分)。谢谢
    • 编辑了问题。请再看一遍。
    • 我已经添加了 RxJava 1 的代码,我收到以下错误:类 'Anonymous class derived from Function' 必须声明为抽象或在 'Function' 中实现抽象方法 'apply(T)'自 1.8+ 起,API 的使用记录为 @ 少... (Ctrl+F1) 此检查发现在其文档中具有 @since 标记的方法的所有用法。当在较新的 SDK 版本下作为生产目标平台执行开发时,这可能很有用。
    • 不过我需要使用以下方法添加数据库:mDatabaseHandler.addProducts(iCat, mProductItemsBelongingToACategory);但在 doOnNext() 方法中,我无法访问 iCat 变量
    • 是的,你有。如果您将doOnNext 放在toList() 之前,您可以访问Pair&lt;String, ProductResponse&gt; -> 一对categoryItem ID 和ProductResponse。如果放在toList() 之后,您可以访问List&lt;Pair&gt;。再次编辑答案。
    猜你喜欢
    • 2015-06-26
    • 1970-01-01
    • 1970-01-01
    • 2021-09-04
    • 2018-06-20
    • 2020-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多