Search code examples
javapaginationretrofitrx-java2flatmap

Using flatMap in RxJava 2.x


I'm working with an API of my own and a i'm hoping to chain a few paginated results using RxJava. I use cursor based pagination. (imagine there are 50 users in this first request):

{
    "data":{
        "status":"ok",
        "total":988, //users total
        "has_next_page":true,
        "end_cursor":"AQAxd8QPGHum7LSDz8DnwIh7yHJDM22nEjd",
        "users":[{"id":"91273813",
                "username":"codergirl",
                "full_name":"Code Girl",
                "picture_url":"https://cdn.com/21603182_7904715668509949952_n.jpg",
                },
                ...
                ]
        }
}

Right now, I'm getting the first 50 results like this, using retrofit:

public class DataResponse {
    @SerializedName("end_cursor")
    private String end_cursor;

    @SerializedName("users")
    private JsonArray users;

    @SerializedName("has_next_page")
    private Boolean has_next_page;

    public boolean hasNextCursor(){
        return has_next_page;
    }
    public String endCursor(){
        if (hasNextCursor()){
            return end_cursor;
        }
        return "";
    }
    public JsonArray getUsers(){
        return users;
    }
}

then:

public interface MyService  {
    @GET( "/users")
    Observable<DataResponse> getUsers(
            @Query("cursor") String cursor,
    );
}

and

MyService service = RetrofitClient.getInstance();
service.getUsers()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe( val->  showUsers(val.getUsers())); // getting the first 50 users

The next call should be to "/users?cursor=AQAxd8QPGHum7LSDz8DnwIh7yHJDM22nEjd"

I'd like to return all (in this case 988) users


Solution

  • My solution

    import io.reactivex.Observer;
    import io.reactivex.Scheduler;
    import io.reactivex.android.schedulers.AndroidSchedulers;
    import io.reactivex.disposables.Disposable;
    import io.reactivex.schedulers.Schedulers;
    
    public void getAllUsers(){
    
        AtomicReference<String> cache = new AtomicReference<>();
        AtomicBoolean hasMore = new AtomicBoolean(true);
    
        io.reactivex.Observable.just(0)
            // getting the first 50 users
            .flatMap(users1-> service.getUsers( cache.get() ))
            
            // scheduler
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            
            // re-call variable
            .repeatUntil(() -> !hasMore.get())
            
            .subscribe(new Observer<DataResponse>() {
                @Override
                public void onSubscribe(Disposable d) { // on subscribe }
    
                @Override
                public void onNext(DataResponse response) {
                    
                    // saving boolean (If there are more users)
                    hasMore.set(response.hasNextCursor());
                    
                    // saving next cursor
                    cache.set(response.endCursor());
                    
                    // adding the new 50 users
                    addToList(response.getUsers());
                    
                }
    
                @Override
                public void onError(Throwable e) { /*error */ }
    
                @Override
                public void onComplete() { /*complete*/ }
            });
    
    }