Skip to content

Instantly share code, notes, and snippets.

@saber-solooki
Created April 26, 2018 11:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save saber-solooki/0db2f49c88657e3f61b9f892d43410ee to your computer and use it in GitHub Desktop.
Save saber-solooki/0db2f49c88657e3f61b9f892d43410ee to your computer and use it in GitHub Desktop.
Detect when the RecyclerView reaches the bottom in Observable manner
package com.saber.ekip.views.rxRecyclerView;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import io.reactivex.Observable;
import static com.saber.ekip.views.rxRecyclerView.Preconditions.checkNotNull;
/**
* Created by sabersolooki on 1/5/18.
*/
public class MyRxRecyclerView {
@CheckResult
@NonNull
public static Observable<Integer> pagingChanges(@NonNull RecyclerView view) {
checkNotNull(view, "view == null");
return new RecyclerViewPagingObservable(view);
}
}
package com.saber.ekip.views.rxRecyclerView;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import com.google.android.flexbox.FlexboxLayoutManager;
import java.util.HashMap;
import java.util.Map;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.MainThreadDisposable;
import static com.saber.ekip.views.rxRecyclerView.Preconditions.checkMainThread;
/**
* Created by sabersolooki on 1/5/18.
*/
final public class RecyclerViewPagingObservable extends Observable<Integer>{
private final RecyclerView view;
RecyclerViewPagingObservable(RecyclerView view) {
this.view = view;
}
@Override
protected void subscribeActual(Observer<? super Integer> observer) {
if (!checkMainThread(observer)) {
return;
}
Listener listener = new Listener(view, observer);
observer.onSubscribe(listener);
view.addOnScrollListener(listener.scrollListener);
if (view.getAdapter() != null) {
view.getAdapter().registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
listener.calculatedPage.clear();
listener.counter = 1;
}
});
}
}
final class Listener extends MainThreadDisposable {
private final RecyclerView recyclerView;
private final RecyclerView.OnScrollListener scrollListener;
private int pastVisibleItems, visibleItemCount, totalItemCount;
private int counter = 1;
private Map<Integer, Integer> calculatedPage = new HashMap<>();
Listener(RecyclerView recyclerView, final Observer<? super Integer> observer) {
this.recyclerView = recyclerView;
final RecyclerView.LayoutManager layoutManager = this.recyclerView.getLayoutManager();
this.scrollListener = new RecyclerView.OnScrollListener() {
@Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
try {
visibleItemCount = layoutManager.getChildCount();
totalItemCount = layoutManager.getItemCount();
if (layoutManager instanceof LinearLayoutManager)
pastVisibleItems = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
else if (layoutManager instanceof FlexboxLayoutManager)
pastVisibleItems = ((FlexboxLayoutManager) layoutManager).findFirstVisibleItemPosition();
else
Log.w("RxRecyclerView", "Your layout manager is not appropriate for paging.");
}
catch (NullPointerException e) {
throw new NullPointerException("Layout manager is null.You should set manager before set observable");
}
if (!calculatedPage.containsKey(totalItemCount)) {
if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
calculatedPage.put(totalItemCount, counter);
counter++;
if (!isDisposed()) {
observer.onNext(counter);
}
}
}
}
};
}
@Override protected void onDispose() {
recyclerView.removeOnScrollListener(scrollListener);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment