最近在使用RxJava的时候遇到了一些问题,情况是这样的:
开发一个搜索结果展示页面,这个页面主要功能是从服务器搜索产品,如果没有搜索到产品就展示推荐商品。

    @Override
    public void search(String key) {
        mModel.search(key)
                .subscribe(new Subscriber<List<Product>>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        mView.showSearchFailed();
                    }

                    @Override
                    public void onNext(List<Product> products) {
                        //
                        if(products.isEmpty()){
                            loadRecommend();
                        }else{
                            mView.showSearchResults(products);
                        }

                    }
                });
    }

    private void loadRecommend(){
        mModel.recommend()
                .subscribe(new Subscriber<List<Product>>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        mView.showSearchFailed();
                    }

                    @Override
                    public void onNext(List<Product> productList) {
                        mView.showRecommendResults(productList);
                    }
                });
    }

这段代码看着没什么问题,但是它打断了RxJava的流。
我尝试把这两个请求合并成一个:

        mModel.search(key)
            .flatMap(new Func1<List<Product>, Observable<List<Product>>>() {
                @Override
                public Observable<List<Product>> call(List<Product> productList) {
                    if(productList.isEmpty()){
                        return mModel.recommend();
                    }else{
                        return Observable.just(productList);
                    }
                       
                }
            }).subscribe(new Subscriber<List<Product>>() {
                @Override
                public void onCompleted() {
                
                }

                @Override
                public void onError(Throwable e) {
                    mView.showSearchFailed();
                }

                @Override
                public void onNext(List<Product> productList) {
                    //这里没有办法区分商品是搜索返回的 还是推荐返回的
                    mView.showSearchResults(productList);
                    mView.showRecommendResults(productList);
                }
            });

对于这个问题的解决有两个方法:

1.通过外部变量来记录控制结果流程

 boolean showSearch = true;
    private void search(String key){
        
        mModel.search(key)
                .flatMap(new Func1<List<Product>, Observable<List<Product>>>() {
                    @Override
                    public Observable<List<Product>> call(List<Product> productList) {
                        if(productList.isEmpty()){
                            showSearch = false;
                            return mModel.recommend();
                        }else{
                            showSearch = true;
                            return Observable.just(productList);
                        }

                    }
                }).subscribe(new Subscriber<List<Product>>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                mView.showSearchFailed();
            }

            @Override
            public void onNext(List<Product> productList) {
                if(showSearch){
                    mView.showSearchResults(productList);
                }else{
                    mView.showRecommendResults(productList);
                }
                
            }
        });
    }

2.自定义可带参数的异常,你需要先自定义一个可传递参数的异常类:

 
    class SearchNoResultException extends RuntimeException {
        List<Product> mProducts;

        SearchNoResultException(List<Product> products) {
            mProducts = products;
        }

        public List<Product> getmProducts() {
            return mProducts;
        }

        public void setmProducts(List<Product> mProducts) {
            this.mProducts = mProducts;
        }
    }

然后在恰当的地方抛出并捕捉它:

 
    private void test2(String key) {

        mModel.search(key)
                .flatMap(new Func1<List<Product>, Observable<List<Product>>>() {
                    @Override
                    public Observable<List<Product>> call(List<Product> productList) {
                        if (productList.isEmpty()) {
                            return mModel.recommend().map(new Func1<List<Product>, List<Product>>() {
                                @Override
                                public List<Product> call(List<Product> productList) {
                                    SearchNoResultException exception = new SearchNoResultException(productList);
                                    throw exception;
                                }
                            });
                        } else {
                            return Observable.just(productList);
                        }

                    }
                }).subscribe(new Subscriber<List<Product>>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                if (e instanceof SearchNoResultException) {
                    SearchNoResultException exception = (SearchNoResultException) e;
                    mView.showRecommendResults(exception.getmProducts());
                } else {
                    mView.showSearchFailed();
                }

            }

            @Override
            public void onNext(List<Product> productList) {
                mView.showSearchResults(productList);

            }
        });
    }

然而,上面的两种方法并不优雅,一个是需要外部变量介入rx的工作流,另一个是通过异常来控制流程。
难道就没有一个方法能够优雅的解决处理这种问题吗? 很抱歉目前我还没找到方案,如果你找到了可以通过邮箱联系我。