Android RXJava2 Retrofit Handling分页

时间:2018-02-06 01:25:46

标签: android observable retrofit2 rx-java2

我在使用RXJava2处理分页时遇到问题。我试图遵循这个post from SO,但它已经过时了。我希望得到一个更新的答案。我正在使用Retrofit,我试图寻找第三方API,直到我得到所有结果。响应如下,但我非常希望通过所有页面并结合所有结果。

目前我的代码如下:

public Observable<WatchList> syncWatchlistSection(String accountId) {
    String sessionToken = mLocal.getSessionId();
    int page = 1;

    return getWatchlistFromServerHelper(sessionToken, accountId, page).concatMap(new Function<WatchList, ObservableSource<? extends WatchList>>() {
        @Override
        public ObservableSource<? extends WatchList> apply(WatchList watchList) throws Exception {
            return Observable.fromArray(watchList);
        }
    });

}

在同一个文件中,辅助文件类似于之前的SO帖子。

private Observable<WatchList> getWatchlistFromServerHelper(String sessionToken, String accountId, int page) {
        return mRestAPI.fetchWatchlistOnServer(sessionToken, accountId, page).concatMap(new Function<WatchList, Observable<WatchList>>() {
            @Override
            public Observable<WatchList> apply(WatchList watchList) throws Exception {
                if (watchList.getPage() == watchList.getTotalPages()) {
                    return Observable.just(watchList);
                }
                return Observable.just(watchList).concatWith(getWatchlistFromServerHelper(sessionToken, accountId, page + 1));
            }
        });
    }

我通过订阅我的活动来调用它。

mSectionLogic.syncWatchlistSection(String.valueOf(account.getId()))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe(new Observer<WatchList>() {
              ... so on ...

这有效,但不处理分页。响应看起来像:

{
  page: 1,
  totalPages: 5,
  results: []
}

我所做的是它应该在page == totalPages时返回。除非它没有结合以前的结果,只返回结果的最后一页。

mRestAPI.fetchWatchlistOnServer是返回Observable<Watchlist>的Retrofit2 Get请求。

我做错了什么?如何将结果与Observable结合起来?最好不要使用Lamda表示法。

我看过的其他资源: - android rxjava2/retrofit2 chaining calls with pagination token

2 个答案:

答案 0 :(得分:0)

您需要构建Observable。您可以使用递归,但如果您有大量页面,则调用堆栈可能会溢出。请参阅答案here

这样的东西
private Observable<WatchList> getWatchlistFromServerHelper(String sessionToken, String accountId, int startPage) {
    int index = startPage;
    BehaviorSubject<Integer> pagecontrol = BehaviorSubject.create(startPage);
    Observable<WatchList> ret = pageControl.asObservable()
                                           .concatMap(new Function<Integer,Observable<WatchList>>()
                                                     {
                                                       Observable<WatchList> apply(Integer page) {
                                                            mRestAPI.fetchWatchlistOnServer(sessionToken, accountId, page)
                                                                    .doOnNext(new Function<watchList -> 
                                                                            (watchList.getPage() == watchList.getTotalPages() ? 
                                                                             Observable.<WatchList>empty().doOnCompleted(()->pageControl.onCompleted()) :
                                                                             pageControl.onNext(page+1)));
                                                        }
                                                     }
                                                     );
    return ret;
}

应该有用。

答案 1 :(得分:0)

我的下面示例代码正常运行,您需要根据自己的要求进行一些修改。

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ProgressBar;

import org.reactivestreams.Publisher;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import butterknife.BindView;
import butterknife.ButterKnife;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.processors.PublishProcessor;

/**
* Created by Akash on 11/11/17.
*/
public class MainActivity extends AppCompatActivity {

private final int VISIBLE_THRESHOLD = 1;
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
@BindView(R.id.progressBar)
ProgressBar progressBar;


private CompositeDisposable mDisposable;
private PublishProcessor<Integer> mPaginator;
private RxPagingAdapter mAdapter;
private boolean isLoading = false;
private int pageNumber = 1;
private int lastVisibleItem, totalItemCount;
private LinearLayoutManager mLayoutManager;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);

    mDisposable = new CompositeDisposable();
    mPaginator = PublishProcessor.create();
    mLayoutManager = new LinearLayoutManager(this);
    recyclerView.setLayoutManager(mLayoutManager);
    mAdapter = new RxPagingAdapter();
    recyclerView.setAdapter(mAdapter);

    // register scroll listener
    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView,
                               int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);

            totalItemCount = mLayoutManager.getItemCount();
            lastVisibleItem = mLayoutManager
                    .findLastVisibleItemPosition();
            if (!isLoading
                    && totalItemCount <= (lastVisibleItem + VISIBLE_THRESHOLD)) {
                pageNumber++;
                mPaginator.onNext(pageNumber);
                isLoading = true;
            }
        }
    });
    subscribeApi();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (!mDisposable.isDisposed())
        mDisposable.dispose();
}

/**
 * Adding to disposable.
 */
private void subscribeApi() {

    mDisposable.add(mPaginator
            .onBackpressureDrop()
            .concatMap(new Function<Integer, Publisher<List<String>>>() {
                @Override
                public Publisher<List<String>> apply(@NonNull Integer page) throws Exception {
                    isLoading = true;
                    progressBar.setVisibility(View.VISIBLE);
                    return apiResponse(page);
                }
            })
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer<List<String>>() {
                @Override
                public void accept(@NonNull List<String> items) throws Exception {
                    mAdapter.addItems(items);
                    mAdapter.notifyDataSetChanged();
                    isLoading = false;
                    progressBar.setVisibility(View.INVISIBLE);
                }
            }));

    mPaginator.onNext(pageNumber);

}

/**
 * This is just sample.
 * You can call api with retrofit interface method which returns Flowable and there you go.
 */
private Flowable<List<String>> apiResponse(final int page) {
    return Flowable.just(true)
            .delay(3, TimeUnit.SECONDS)
            .map(new Function<Boolean, List<String>>() {
                @Override
                public List<String> apply(@NonNull Boolean value) throws Exception {
                    List<String> items = new ArrayList<>();
                    for (int i = 1; i <= 10; i++) {
                        items.add("Item " + (page * 10 + i));
                    }
                    return items;
                }
            });
}
}
  

适配器类方法

 void addItems(List<String> items) {
    this.itemArrayList.addAll(items);
 }

Source : GitHub