0

I have the following issue in my Android project:

I have a list of elements (ArrayList) obtained from a previous network call using Retrofit. CategoryItem looks like this:

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;
   }
}

Practically the categories is made of 20 elements. Now I need to make a network API and obtain the list of products for each of the categories. In order to do so, the products API has the id from the category as query parameter. After I obtain the list of products of a certain categoy I am adding it into internal SQLite DB.

I would like to do this with RxJava (either 1 and 2).

What I have done up to now is not multi-threaded and is on the MainThread which is not correct. I will add the code snippet here:

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);

}

I would like to do this with flatMap or flatMapIterable and eventually using multi-threading.

1 Answer 1

9

RxJava has an equivalent of for loop:

Observable.from(...) //RxJava1

or

Observable.fromIterable(...) //RxJava2

Applying that would allow you for iterating over CategoryItem list. Then each categoryItem.getId() must be paired with the result from getProductsRx() API call. And then merge all results into single list with toList() This would look like that:

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())

Written in RxJava2.

Above are only Observables. You can still use you Subscriber and save data to database in onNext(). However, you might also use doOnNext() operator after toList() to save data in database.

Sign up to request clarification or add additional context in comments.

9 Comments

Two issues: a) Can you give an example also in RxJava 1? b) where I can save to the database? (please check the question because there I had the part where to save it to the DB). Thanks
Edited the question. Please, look again.
I have added the code for RxJava 1 and I receive the following error: Class 'Anonymous class derived from Function' must either be declared abstract or implement abstract method 'apply(T)' in 'Function' Usage of API documented as @ since 1.8+ less... (Ctrl+F1) This inspection finds all usages of methods that have @since tag in their documentation. This may be useful when development is performed under newer SDK version as the target platform for production.
Nevertheless I need to add DB using: mDatabaseHandler.addProducts(iCat, mProductItemsBelongingToACategory); but in the method doOnNext() I don't have acccess to iCat variable
Yes you have. If you put doOnNext before toList() you have access to Pair<String, ProductResponse> -> Pair of categoryItem ID and ProductResponse. If put after toList() you have access to List<Pair<String, ProductResponse>>. Edited the answer once again.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.