将可观察的数据传递给另一个,是否需要嵌套?

时间:2017-05-23 10:54:45

标签: android rx-java

我有代码示例:

private Observable<String> rxFetch() {
        return Observable.fromCallable(() -> fetchWebsiteHtml())//fetch source of html
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .doOnError(throwable -> Toast.makeText(this, "Connection problem", Toast.LENGTH_SHORT).show())
                .onErrorResumeNext(Observable.empty())
                .doOnNext(s ->
                        rxGetHotMovies(s)//fetch from html some html tags
                                .observeOn(AndroidSchedulers.mainThread())
                                .subscribeOn(Schedulers.io())
                                .doOnError(throwable -> {
                                    Toast.makeText(this, "Parse list failed somehow", Toast.LENGTH_SHORT).show();
                                })
                                .onErrorResumeNext(Observable.empty())
                                .doOnNext(
                                        hotMovies ->
                                                rxLoastToListView(hotMovies)//fill list with data
                                                        .doOnError(throwable -> Toast.makeText(this, "Filling list problem", Toast.LENGTH_SHORT).show())
                                                        .onErrorResumeNext(Observable.empty())
                                                        .doOnComplete(() -> Log.d(TAG, "rxFetch: xxxxxx"))
                                                        .subscribe()
                                )
                                .subscribe(hotMovies -> {
                                    for (int i = 0; i < hotMovies.size(); i++) {
                                        Log.d(TAG, "fetch list item: " + hotMovies.get(i).toString());
                                    }
                                })
                );
    }

这个可观察的rxFetch确实:

  1. 在单独的帖子中下载html源代码
  2. 当错误 - 显示错误消息
  3. 成功时 - &gt; onNext - &gt;获取html并在单独的线程中获取一些html标签
  4. 当错误 - 显示错误消息msg
  5. 成功时 - 将数据传递给listview并在适配器中显示结果
  6. 我的问题是:当我们对其中一个观察者返回另一个必要数据时,是否需要进行嵌套?我想不嵌套observables,但第一个返回数据 - 并且它不允许我使用例如zip,对吧?

2 个答案:

答案 0 :(得分:1)

您可能正在寻找flatMap运算符,它允许您链接反应流。

我会用这种方式重写你的代码:

Observable.fromCallable(() -> fetchWebsiteHtml())
    .flatMap(s -> rxGetHotMovies(s))
    .subscribeOn(Schedulers.io()) 
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(hotMovies -> {
        // update UI here
    }, throwable -> {
        // check throwable type and show appropriate error message
    }); 

答案 1 :(得分:1)

习惯的方式是这样的:

private Observable<String> rxFetch() {
    return Observable.fromCallable(() -> fetchWebsiteHtml())//fetch source of html
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .doOnError(throwable -> Toast.makeText(this, "Connection problem", Toast.LENGTH_SHORT).show())
            .onErrorResumeNext(Observable.empty())
            .flatMap(s -> rxGetHotMovies(s)
                  .observeOn(AndroidSchedulers.mainThread())
                  .subscribeOn(Schedulers.io())
            .doOnError(throwable -> 
                  Toast.makeText(this, "Parse list failed somehow", Toast.LENGTH_SHORT).show())
            .onErrorResumeNext(Observable.empty())
            .flatMap(hotMovies -> rxLoastToListView(hotMovies)
                  .observeOn(AndroidSchedulers.mainThread())
                  .subscribeOn(Schedulers.io())
            .doOnError(throwable -> Toast.makeText(this, "Filling list problem", Toast.LENGTH_SHORT).show())
            .onErrorResumeNext(Observable.empty())
            .doOnComplete(() -> Log.d(TAG, "rxFetch: xxxxxx"))
            .subscribe(hotMovies -> {
               for (int i = 0; i < hotMovies.size(); i++) {
                  Log.d(TAG, "fetch list item: " + hotMovies.get(i).toString());
             });
}

但是,我建议您抽象出错误处理:

private static <T> Transformer<T, T> whenErrorToast(Function<E extends Throwable, String> messageComposer) {
   return source -> source.onErrorResumeNext(e -> Observable
       .just(messageComposer.apply(e))
       .subscribeOn(AndroidSchedulers.mainThread())
       .doOnNext(msg -> Toast.makeText(this, msg Toast.LENGTH_SHORT).show())
       .observeOn(Schedulers.io())
       .flatMap(msg -> Observable.empty());
}

private Observable<String> rxFetch() {
    return Observable.fromCallable(() -> fetchWebsiteHtml())//fetch source of html
            .compose(whenErrorToast(e -> "Connection problem"))
            .flatMap(s -> rxGetHotMovies(s))
            .compose(whenErrorToast(e -> "Parse list failed somehow"))
            .flatMap(hotMovies -> rxLoastToListView(hotMovies))
            .compose(whenErrorToast(e -> "Filling list problem"))
            .doOnComplete(() -> Log.d(TAG, "rxFetch: xxxxxx"))
            .subscribe(hotMovies -> {
               for (int i = 0; i < hotMovies.size(); i++) {
                  Log.d(TAG, "fetch list item: " + hotMovies.get(i).toString());
             });
}