我在使用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
答案 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);
}