Search code examples
androidrx-javaretrofit2mosby

Load more on retrofit and rxJava


I'm trying load posts from blog. I use mosby + retrofit + rxjava.

public class PostRepository implements IPostRepository {

    private Api api;

    private long last_id = 0;
    private Single<List<Post>> postList;

    public PostRepository(Api api) {
        this.api = api;
    }

    @Override
    public Single<List<Post>> getList() {
        this.load();
        return postList;
    }

    private void load() {
        Single<List<Post>> tmp;
        Log.d(Configuration.DEBUG_TAG, "Loading " + last_id);
        tmp = api.getPostList(last_id)
            .map(posts -> {
                ArrayList<Post> postList = new ArrayList<>();
                for (PostResponse post : posts) {
                    if (last_id == 0 || last_id > post.id) {
                        last_id = post.id;
                    }
                    postList.add(new Post(
                            post.id,
                            post.thumb,
                            post.created_at,
                            post.title
                    ));
                }
                return postList;
            });
        if (postList == null) {
            postList = tmp;
        } else {
            postList.mergeWith(tmp);
        }
    }

    @Override
    public Single<Post> getDetail(long id) {
        return api.getPost(id)
                .map(postResponse -> new Post(
                        postResponse.id,
                        postResponse.thumb,
                        postResponse.created_at,
                        postResponse.title,
                        postResponse.body
                ));
    }
}

and api

public interface Api {
    @GET("posts")
    Single<PostListResponse> getPostList(@Query("last_id") long last_id);

    @GET("post/{id}")
    Single<PostResponse> getPost(@Path("id") long id);
}

First query to website is ok. https://site/posts?last_id=0

But second run function getList does not work. I always get the same get query with last_id = 0, but line in console write

D/App: Loading 1416
D/App: 1416
D/OkHttp: --> GET https://site/posts?last_id=0 http/1.1

if i write

tmp = api.getPostList(1000)

then i get true query string https://site/posts?last_id=1000

Update I rewrite code repository.

public class PostRepository implements IPostRepository {

    private Api api;

    private long last_id = 0;
    private List<Post> postList = new ArrayList<>();
    private Observable<List<Post>> o;

    public PostRepository(Api api) {
        this.api = api;
    }

    @Override
    public Single<List<Post>> getList() {
        return load();
    }

    private Single<List<Post>> load() {
        return api.getPostList(last_id)
            .map(posts -> {
                for (PostResponse post : posts) {
                    if (last_id == 0 || last_id > post.id) {
                        last_id = post.id;
                    }
                    postList.add(new Post(
                            post.id,
                            post.thumb,
                            post.created_at,
                            post.title
                    ));
                }
                return postList;
            });
    }

    @Override
    public Single<Post> getDetail(long id) {
        return api.getPost(id)
                .map(postResponse -> new Post(
                        postResponse.id,
                        postResponse.thumb,
                        postResponse.created_at,
                        postResponse.title,
                        postResponse.body
                ));
    }
}

It's work


Solution

  • Your problem lies in this code fragment:

    if (postList == null) {
        postList = tmp;
    } else {
        postList.mergeWith(tmp); // here
    }
    

    Operators on observables are performing immutable operations, which means that it always returns new stream which is a modified version of the previous one. That means, that when you apply mergeWith operator, the result of this is thrown away as you are not storing it anywhere. The most easy to fix this is to replace the old postList variable with the new stream.

    However, this is not optimal way of doing this. You should have a look on Subjects and emit new values within the old stream as your current solution will not affect previous subscribers as they have subscribed to a different stream