简体   繁体   English

用RxJava替换嵌套的Retrofit调用

[英]Replace nested Retrofit calls with RxJava

Firstly, let me begin this by saying that I'm relatively new to RxJava so please bear with me as I grasp the basics. 首先,让我先说说我对RxJava相对较新,因此在我掌握基本知识的同时请耐心等待。 :) :)

I basically understand the whole subscribe[On|With]() beginner type of stuff (more or less). 我基本上了解整个subscribe[On|With]()初学者的类型(或多或少)。 I'm trying however to do something a tad bit more complicated, and JavaRx seems perfect for this kind of thing. 但是我正在尝试做一些更复杂的事情,而JavaRx对于这种事情似乎很完美。

I have a curated movie database that I'm querying movie details from. 我有一个精选的电影数据库,可以从中查询电影详细信息。 Now, the API here is a bit weird. 现在,这里的API有点奇怪。 You have to make two calls to get everything about a movie. 您必须打两个电话才能获得电影的所有内容。 The first API call yields the id, title, categories and rating and the second one other important stuff like the description, trailer etc. As you might have guessed, you need the movieId from part1 to get the extra info. 第一个API调用产生id,标题,类别和等级,第二个API产生描述,预告片等其他重要内容。您可能已经猜到,您需要part1中的movieId来获取额外的信息。 Nested calls work here, but they are by no means considered best practice. 嵌套调用在这里可以工作 ,但绝不是最佳实践。

My code looks something like this: 我的代码如下所示:

pageSingle.subscribeOn(Schedulers.io())
        .subscribeWith(new DisposableSingleObserver<mPage>() {
            @Override public void onSuccess(mPage value) {
                moviesInPage = value.movies;
                if(moviesInPage==null){
                    Log.w(TAG, "mergeMovieParts: no movies returned");
                }else {
                    for (int i = 0; i < moviesInPage.size(); i++) {
                        final fMovie firstMovie = moviesInPage.get(i);
                        apiService.getSecondPart(firstMovie.id)
                                .subscribeWith(new DisposableSingleObserver<sMovie>() {
                            @Override 
                            public void onSuccess(sMovie secondMovie) {
                                mergeMovieParts(firstMovie, secondMovie);
                                }
                            @Override 
                            public void onError(Throwable e) {
                                e.printStackTrace();
                                }
                        });
                    }
                }

            }
            @Override public void onError(Throwable e) {
                handleError(e);
            }
        });

with pageSingle also being a Single . pageSingle也是Single You can probably see why this isn't guaranteed to work all the time. 您可能会明白为什么不能保证始终都能正常工作。 Single.zip() won't work here, as I need information (the id more specifically) from the first call to start the second one. Single.zip()在这里不起作用,因为我需要从第一个调用开始的信息(更具体地说是id )以开始第二个调用。 My question boils down to: 我的问题归结为:

  1. how do I go about replacing those nested Retrofit calls with JavaRx ones? 我该如何用JavaRx替换那些嵌套的Retrofit调用? Please note that mPage returns a List<fMovie> object. 请注意, mPage返回一个List<fMovie>对象。

  2. at the moment, I'm doing these calls one after the other. 目前,我正在依次接听这些电话。 Is it possible to fetch the movie list and based on this to make multiple calls simultaneously to fetch the second part? 是否可以获取电影列表,并以此为基础同时进行多个调用以获取第二部分? I'm guessing multi-threading is the answer here, but how do I go about it in RxJava and what are the implications eg is it worth it, in your opinion or are the tradeoffs (if any) to big? 我猜这里是多线程的解决方案,但是我如何在RxJava中使用它呢?有什么含义呢?例如,在您看来还是值得的?或者权衡利弊(如果有的话)?

  3. unrelated to this question, but do you have any suggestions of books, videos etc. I could read/watch that would help me catch up with RxJava the most. 与这个问题无关,但是您对书籍,视频等有什么建议吗?我可以阅读/观看,这将最有助于我赶上RxJava。 It excites me a lot, but at the same time I feel it's a bit too overwhelming to learn everything by "reading the documentation". 这让我很兴奋,但是与此同时,我觉得通过“阅读文档”来学习所有内容实在有点不堪重负。

If I wasn't clear enough, please don't hesitate to ask for more context/ clarification. 如果我不够清楚,请随时询问更多背景信息/说明。 Thanks in advance! 提前致谢!

EDIT : the error I get with flatMap() : 编辑 :我用flatMap()得到的错误:

Error:(109, 17) error: no suitable method found for flatMap(<anonymous Function<Movie1,ObservableSource<?>>>)
method Observable.<R#1>flatMap(Function<? super Object,? extends ObservableSource<? extends R#1>>) is not applicable
(cannot infer type-variable(s) R#1
(argument mismatch; <anonymous Function<Movie1,ObservableSource<?>>> cannot be converted to Function<? super Object,? extends ObservableSource<? extends R#1>>))
method Observable.<R#2>flatMap(Function<? super Object,? extends ObservableSource<? extends R#2>>,boolean) is not applicable
(cannot infer type-variable(s) R#2
(actual and formal argument lists differ in length))
method Observable.<R#3>flatMap(Function<? super Object,? extends ObservableSource<? extends R#3>>,boolean,int) is not applicable
(cannot infer type-variable(s) R#3
(actual and formal argument lists differ in length))
method Observable.<R#4>flatMap(Function<? super Object,? extends ObservableSource<? extends R#4>>,boolean,int,int) is not applicable
[...]

My implementation: 我的实现:

movieService.getMoviesFromPath(path)
                .subscribeOn(Schedulers.io())
                .flattenAsObservable(new Function<MoviePage, Iterable<?>>() {
                    @Override
                    public Iterable<?> apply(MoviePage moviePage) throws Exception {
                        return moviePage.movieList;  // movieList is a List<Movie1>
                    }
                })
                .flatMap(new Function<Movie1, ObservableSource<?>>() {
                    @Override
                    public ObservableSource<?> apply(Movie1 movie1) throws Exception {
                        return null;
                    }
                });

It seems you would need something like the following: 似乎您需要以下内容:

movieService.getPage()
    .flattenAsObservable(page -> page.movies)
    .flatMap(movie -> apiService.getSecondPart(movie.movieId))

Or, taking away the lambdas, 或者,拿走lambda,

movieService.getPage()
            .flattenAsObservable(new Function<Page, Iterable<Movie>>() {
                @Override
                public Iterable<Movie> apply(Page page) throws Exception {
                    return page.movies;
                }
            })
            .flatMap(new Function<Movie, ObservableSource<DetailedMovie>>() {
                @Override
                public ObservableSource<DetailedMovie> apply(Movie movie) throws Exception {
                    return apiService.getSecondPart(movie.movieId);
                }
            })

That being said, writing something like new DisposableSingleObserver<mPage> in the original post is a bad sign. 话虽这么说,在原始帖子中写类似new DisposableSingleObserver<mPage>东西是一个不好的信号。 Before continuing with Rx, it may be worth your time learning about Generics in Java since this is the cause of your second error. 在继续使用Rx之前,可能值得您花一些时间来学习Java中的泛型,因为这是第二个错误的原因。

You probably need to have a good working knowledge of generics ( and standard Java naming practices ) to get the most out of RxJava. 为了充分利用RxJava,您可能需要对泛型( 和标准Java命名惯例 )有很好的了解。 Good luck! 祝好运!

Note the two examples assume that subscribeOn(Schedulers.io()) is implicit and configured at the level of Retrofit. 请注意,这两个示例假定subscribeOn(Schedulers.io())是隐式的,并在翻新级别进行配置。 You can see how to do this in these answers 您可以在这些答案中查看如何执行此操作

Update : if you want to merge the two Movie objects together I suppose you could do: 更新 :如果您想将两个Movie对象合并在一起,我想您可以这样做:

    movieService.getPage()
            .flattenAsObservable(new Function<Page, Iterable<? extends Movie>>() {
                @Override
                public Iterable<? extends Movie> apply(Page page) throws Exception {
                    return page.movies;
                }
            })
            .flatMap(new Function<Movie, ObservableSource<DetailedMovie>>() {
                @Override
                public ObservableSource<DetailedMovie> apply(Movie movie) throws Exception {
                    return apiService.getSecondPart(movie.movieId).toObservable();
                }
            }, new BiFunction<Movie, DetailedMovie, MergedMovie>() {
                @Override
                public MergedMovie apply(Movie movie, DetailedMovie detailedMovie) throws Exception {
                    return new MergedMovie(movie, detailedMovie);
                }
            });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM