简体   繁体   中英

Retrofit + rxJava: how to implement iterable N requests?

I have a problem to implement following problem: I'm making a request that fetches all active leagues. Then, for each of them I need to make another request to grab the matches. I think it's possible to implement the solution using flatMapIterable, but don't know how.

For now I have following retrofit interfaces:

public interface LeaguesApi
{
    @GET("/api/get-leagues")
    Observable<ArrayList<League>> getLeagues(@Query("active_only") boolean activeOnly);
}

public interface LeagueApi
{
    @GET("/api/get-league-fixtures/{leagueId}")
    Observable<ArrayList<Match>> getMatchesPlayed(@Path("leagueId") int leagueId, @Query("played") boolean played);
}

Please advise how to iterate through all leagues in order to perform getMatchesPlayed for each of them. Best would be without lambda expressions, since I'm not using them in my project.

Try this code:

leaguesApi              // your REST adapter from retrofit
                .getLeagues(true)    // fetch leagues
                .flatMapIterable(leagues -> leagues)    //Transform from ArrayList<Liague> to Observable<Liague>
                .flatMap(l -> leagueApi.getMatchesPlayed(l.getId(), true))
                .subscribe(
                        (match) -> {/*This is onNext*/},
                        t -> t.printStackTrace(), //onError
                        () -> {/*onComplete*/}
                );

UPDATE:

Without lambdas:

leaguesApi              // your REST adapter from retrofit
                .getLeagues(true)    // fetch leagues
                .flatMapIterable(new Func1<ArrayList<League>, Iterable<?>>() {
                    @Override
                    public Iterable<?> call(ArrayList<League> leagues) {
                        return leagues;
                    }
                })    //Transform from ArrayList<Liague> to Observable<Liague>
                .flatMap(new Func1<League, Observable<Match>>() {
                    @Override
                    public Observable<Match> call(League l) {
                        return leagueApi.getMatchesPlayed(l.getId(), true);
                    }
                })
                .subscribe(
                        new Action1<Match>() {
                            @Override
                            public void call(Match match) {
                                //onNext
                            }
                        },
                        new Action1<Throwable>() {
                            @Override
                            public void call(Throwable throwable) {
                                //onError
                            }
                        },
                        new Action0() {
                            @Override
                            public void call() {
                                //onComplete
                            }
                        }
                );

I'd change that API so it reads like this otherwise you lose a lot of the flexibility of streams:

public interface LeaguesApi
{
    @GET("/api/get-leagues")
    Observable<League> getLeagues(@Query("active_only") boolean activeOnly);
}

public interface LeagueApi
{
    @GET("/api/get-league-fixtures/{leagueId}")
    Observable<Match> getMatchesPlayed(@Path("leagueId") int leagueId, @Query("played") boolean played);
}

Can you do that?

If not then to get Observable<T> from Observable<ArrayList<T>> you do:

observable.flatMapIterable(
    new Func1<ArrayList<T>, ArrayList<T>>() {
        @Override
        public ArrayList<T> call(ArrayList<T> list) {
            return list;
        }
    });

much nicer to just say observable.flatMapIterable(x -> x) of course.

To get all played matches for all active leagues just do this:

Observable<League> leagues= getLeagues(true);
Observable<Match> matches =
    leagues.flatMap( league -> getMatchesPlayed(league.leagueId, true));

or without lambdas (I wish you hadn't asked for that)

Observable<Match> matches = leagues.flatMap(
    new Func1<League, Observable<Match>> () {
        @Override
        public Observable<Match> call(League league) {
            return getMatchesPlayed(league.leagueId, true);
        }
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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