简体   繁体   English

Android RXJava2改造处理分页

[英]Android RXJava2 Retrofit Handling paging

I'm having issues handling paging with RXJava2. 我在处理RXJava2分页时遇到问题。 I tried to follow this post from SO but it was dated. 我尝试遵循SO的这篇文章,但它已过时。 I was hoping to get a more up to date answer. 我希望得到一个最新的答案。 I'm using Retrofit and I'm trying to page a third party API till I have all of the results. 我正在使用Retrofit,并尝试分页第三方API,直到获得所有结果为止。 The response is below but I pretty much want to through all pages and combine all results. 响应如下,但是我非常想浏览所有页面并合并所有结果。

Currently my code is as follows: 目前,我的代码如下:

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);
        }
    });

}

And in the same file the helper file similar to the previous SO post. 并且在同一文件中,帮助程序文件类似于先前的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));
            }
        });
    }

I'm calling this via a subscribe on my activity. 我通过订阅我的活动来称呼它。

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

This works but doesn't handle the paging. 这有效,但不处理分页。 The response looks something like: 响应类似于:

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

What I've done is it should return when page == totalPages . 我所做的是,它应该在page == totalPages时返回。 Except it doesn't combine the previous results and just returns the last page of results. 除非它不合并先前的结果,而仅返回结果的最后一页。

mRestAPI.fetchWatchlistOnServer is the Retrofit2 Get request that returns Observable<Watchlist> . mRestAPI.fetchWatchlistOnServer是Retrofit2 Get请求,该请求返回Observable<Watchlist>

What am I doing wrong? 我究竟做错了什么? How do I combine results with Observable? 如何将结果与可观察值结合? Preferably not in Lamda notation. 最好不要使用Lamda表示法。

Other resources I looked at: - android rxjava2/retrofit2 chaining calls with pagination token 我查看过的其他资源:- 具有分页令牌的android rxjava2 / retrofit2链接调用

You need to build the Observable. 您需要构建Observable。 You can use recursion but if you have large number of pages your calling stack might overflow. 您可以使用递归,但是如果您有大量页面,则调用堆栈可能会溢出。 See the answer here 这里查看答案

Something like 就像是

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;
}

should work. 应该管用。

My below sample code is working, here you need to make some modifications according to your requirements. 我下面的示例代码正在运行,在这里您需要根据需要进行一些修改。

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;
                }
            });
}
}

Adapter class method 适配器类方法

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

Source : GitHub 来源:GitHub

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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