1

First of all, let me show the UI enter image description here

First, query list of Head from remote server API1 by parameter tab1 and return list. Second, traverse list and query the body list for every Head through API2 and combine the head and corresponding list. Finally, after finish traversal, return List<Wrapper<Head, List>> data to show the UI.

It's better to use one RxJava block combine with Retrofit. My solution is as below, but it's not elegant enough. This should be a very common requirement so that it is better have a better solution for anyone to reference.

Thanks for all in advance. Hope I have described the requirement clearly.

First. query list of Header.

    public void queryListData(LifecycleOwner lifecycleOwner, MaterialZone mz, int pageNum) {
    VersaApiService.INSTANCE.getService(MaterialService.class)
            .queryMaterialCategory(/*mz.getZoneId()*/"9223372036854775807", mVerticalPageNum, VERTICAL_PAGE_SIZE)
            .compose(RxUtil.applyScheduler(lifecycleOwner))
            .map(new Function<PageModel<Header>, List<Header>>() {
                @Override
                public List<Header> apply(@NonNull PageModel<Header> pageResult) throws Exception {
                    return pageResult.getResult().getRecords();
                }
            })
            .subscribe(new Consumer<List<Header>>() {
                @Override
                public void accept(List<Header> headers) throws Exception {
                    mHeader.setValue(headers);
                }
            }, new Consumer<Throwable>() {
                @Override
                public void accept(Throwable throwable) throws Exception {
                    VLog.d(HORIZONTAL_PAGE_SIZE + ", " + VERTICAL_PAGE_SIZE);
                    VLog.d("onError");
                }
            }, new Action() {
                @Override
                public void run() throws Exception {
                    // Complete
                    VLog.d("onComplete");
                }
            });
}

Second. Query list of Body for every Header in traversal.

    private MediatorLiveData<List<HeaderBodyWrapper>> mGroups = new MediatorLiveData<>();
    private MutableLiveData<List<Header>> mHeader = new MutableLiveData<>();
    public void init(LifecycleOwner lifecycleOwner) {
        mGroups.addSource(mHeader, value -> {
            queryBodyList(lifecycleOwner, value);
        });
    }
    public void queryBodyList(LifecycleOwner lifecycleOwner, List<Header> headers) {
    List<HeaderBodyWrapper> result = new ArrayList<>();
    for (Header header : headers) {
        VersaApiService.INSTANCE.getService(MaterialService.class)
                .queryMaterial(header.getCategoryId(), mVerticalPageNum, VERTICAL_PAGE_SIZE)
                .compose(RxUtil.applyScheduler(lifecycleOwner))
                .map(new Function<PageModel<Body>, List<Body>>() {
                    @Override
                    public List<Body> apply(@NonNull PageModel<Body> materialGroupPageModel) throws Exception {
                        return materialGroupPageModel.getResult().getRecords();
                    }
                })
                .subscribe(new Consumer<List<Body>>() {
                    @Override
                    public void accept(List<Body> bodies) throws Exception {
                        // Combine header and body list.
                        HeaderBodyWrapper wrapper = new HeaderBodyWrapper();
                        wrapper.setMaterialGroup(header);
                        wrapper.setMaterials(bodies);
                        result.add(wrapper);
                        VLog.d("onNext");
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        VLog.d(HORIZONTAL_PAGE_SIZE + ", " + VERTICAL_PAGE_SIZE);
                        VLog.d("onError");
                    }
                }, new Action() {
                    @Override
                    public void run() throws Exception {
                        // Complete
                        VLog.d("onComplete");
                        // TODO: Set value when all query.
                        if (result.size() == headers.size()) {
                            mGroups.setValue(result);
                        }
                    }
                });
    }
}
Saint
  • 1,492
  • 1
  • 11
  • 20

1 Answers1

0

Here is my new solution without interacting with live data, but still is not elegant because of nested subscribe.

    public void queryListData2(LifecycleOwner lifecycleOwner, MaterialZone mz) {
        VersaApiService.INSTANCE.getService(MaterialService.class)
                .queryMaterialCategory(/*mz.getZoneId()*/"9223372036854775807", mVerticalPageNum, VERTICAL_PAGE_SIZE)

                .map(new Function<PageModel<Header>, List<Header>>() {
                    @Override
                    public List<Header> apply(@NonNull PageModel<Header> materialGroupPageModel) throws Exception {
                        return materialGroupPageModel.getResult().getRecords();
                    }
                })
                .concatMap(new Function<List<Header>, ObservableSource<List<HeaderBodyWrapper>>>() {
                    @Override
                    public ObservableSource<List<HeaderBodyWrapper>> apply(@NonNull List<Header> groups) throws Exception {
                        MaterialService ms = VersaApiService.INSTANCE.getService(MaterialService.class);
                        List<HeaderBodyWrapper> result = new ArrayList<>();
                        // Retrieve the list of header, then query their body list one by one.
                        // Combine the header and bodies and add into list, return the list
                        // to update UI finally.
                        // TODO: nested subscribe here is not elegant, try to combine observers
                        //  below to be Observer<HeaderBodyWrapper>
                        for (Header group : groups) {
                            HeaderBodyWrapper mcw = new HeaderBodyWrapper();
                            Observable<PageModel<Body>> observable = ms.queryMaterial(group.getCategoryId(), 0, 100);
                            observable.subscribe(
                                    new Consumer<PageModel<Body>>() {
                                        @Override
                                        public void accept(PageModel<Body> bodyPageModel) throws Exception {
                                            mcw.setMaterialGroup(group);
                                            PageModel.Result<Body> body = bodyPageModel.getResult();
                                            if (body != null && body.getTotal() > 0) {
                                                mcw.setMaterials(body.getRecords());
                                            }
                                            result.add(mcw);
                                        }
                                    },
                                    new Consumer<Throwable>() {
                                        @Override
                                        public void accept(Throwable throwable) throws Exception {

                                        }
                                    }, new Action() {
                                        @Override
                                        public void run() throws Exception {

                                        }
                                    });

                        }
//                        Observable.concat()
                        return Observable.just(result);
                    }
                })
                .compose(RxUtil.applyScheduler(lifecycleOwner))
                .subscribe(new Consumer<List<HeaderBodyWrapper>>() {
                    @Override
                    public void accept(List<HeaderBodyWrapper> pageModel) throws Exception {
                        Gson gson = new Gson();
                        String result = gson.toJson(pageModel);
                        VLog.d(Thread.currentThread().getId() + " result");
                        VLog.d("onNext: " + result);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        VLog.d(HORIZONTAL_PAGE_SIZE + ", " + VERTICAL_PAGE_SIZE);
                        VLog.d("onError");
                    }
                }, new Action() {
                    @Override
                    public void run() throws Exception {
                        // Complete
                        VLog.d("onComplete");
                    }
                });
    }
Saint
  • 1,492
  • 1
  • 11
  • 20