使用RxJava的无限滚动RecycleView

时间:2017-04-02 07:41:19

标签: android rx-java rx-android rx-java2

好的家伙,首先我已经阅读了这篇blog帖子(使用RxJS Observables进行反应性编程的Naive Infinite滚动),并希望在Android上使用RecycleView进行尝试。

这是结果和我的代码......

RESULT

enter image description here

活性

public class MainActivity extends AppCompatActivity {

    private final String[] NAME = {"JONG", "MARCH", "BANK", "TAR", "VIJAYA", "JAMES", "OAT", "POOH", "BOW", "NAN"};

    private int currentPage = 1;
    private RecyclerView rcvInfinite;
    private MainAdapter adapter;
    private ArrayList<MainListItem> listItems = new ArrayList<>();
    private boolean isFetchingApi;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        rcvInfinite = (RecyclerView) findViewById(R.id.rcvInfinite);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("PAGE", currentPage);
        outState.putParcelableArrayList("LISTITEM", listItems);
    }

    @Override
    protected void onPostCreate(@Nullable Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        if (savedInstanceState != null) {
            currentPage = savedInstanceState.getInt("PAGE", currentPage);
            listItems = savedInstanceState.getParcelableArrayList("LISTITEM");
        }

        if (listItems == null || listItems.isEmpty()) {
            listItems = getListItem(currentPage);
            ++currentPage;
        }

        adapter = new MainAdapter(this, listItems);
        rcvInfinite.setLayoutManager(new LinearLayoutManager(this));
        rcvInfinite.setScrollbarFadingEnabled(false);
        rcvInfinite.setNestedScrollingEnabled(true);
        rcvInfinite.setAdapter(adapter);

        ScrollDownPercentageObservable scrollDownPercentageObservable =
                new ScrollDownPercentageObservable(rcvInfinite, 70);

        Observable.create(scrollDownPercentageObservable)
                .filter(scroll70f -> {
                    if (scroll70f && !isFetchingApi) {
                        isFetchingApi = true;
                        return true;
                    } else {
                        return false;
                    }
                })
                .concatMap(scroll70f -> fetchRemoteData())
                .delay(2000, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe((next) -> {
                    ++currentPage;
                    listItems.addAll(next);
                    adapter.setItems(listItems);
                    adapter.notifyDataSetChanged();
                    isFetchingApi = false;
                }, (error) -> {
                    error.printStackTrace();
                }, () -> {
                });
    }

    private Observable<ArrayList<MainListItem>> fetchRemoteData() {
        return Observable.create(e -> {
            // mock data
            ArrayList<MainListItem> listItems1 = getListItem(currentPage);

            // emit
            e.onNext(listItems1);
            e.onComplete();
        });
    }

    @NonNull
    private ArrayList<MainListItem> getListItem(int page) {
        ArrayList<MainListItem> listItems = new ArrayList<>();
        int lastIndex = page * 10;
        int firstIndex = lastIndex - (10 - 1);
        for (int i = firstIndex; i <= lastIndex; i++) {
            listItems.add(new MainListItem(String.format(Locale.getDefault(), "%03d", i), NAME[i % 10]));
        }
        return listItems;
    }

    private class ScrollDownPercentageObservable implements ObservableOnSubscribe<Boolean> {

        private final RecyclerView mRecycleView;
        private final int mPercentage;
        private ObservableEmitter<Boolean> emitter;

        public ScrollDownPercentageObservable(RecyclerView recycleView, int percentage) {
            mRecycleView = recycleView;
            mPercentage = percentage;
            mRecycleView.addOnScrollListener(onScroll);
        }

        private RecyclerView.OnScrollListener onScroll = new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView rcv, int dx, int dy) {
                super.onScrolled(rcv, dx, dy);
                if (emitter != null) {
                    if (dy > 0) {
                        // Scrolling up
                        Log.v("SCROLL", "SCROLL UP");
                        LinearLayoutManager lm = (LinearLayoutManager) rcv.getLayoutManager();
                        int pos = lm.findLastVisibleItemPosition();
                        int itemCount = rcv.getAdapter().getItemCount();
                        int itemViewedPercentage = (int) ((pos / (float) itemCount) * 100);
                        emitter.onNext(itemViewedPercentage >= mPercentage);
                    } else {
                        // Scrolling down
                        Log.v("SCROLL", "SCROLL DOWN");
                        emitter.onNext(false);
                    }
                }
            }
        };

        @Override
        public void subscribe(ObservableEmitter<Boolean> e) throws Exception {
            emitter = e;
        }
    }
}

它在结果中显示,但我想知道,是否有任何RxJava方法可以在不使用以下标志的情况下实现相同的结果?

  

boolean isFetchingApi;

为什么我使用它?

这是因为当onScrolled满足条件(滚动到70%的项目)时,observable将非常快地发出项目。每页请求api(模拟数据)的结果太多时间。总之,此标志用于停止接收来自onScrolled的结果流。

任何想法,或者,谢谢。

0 个答案:

没有答案