Skip to content

Commit

Permalink
- fixed incorrect offset determining with not empty emptyCount
Browse files Browse the repository at this point in the history
- build pattern for PaginationTool
  • Loading branch information
matzuk committed Dec 24, 2015
1 parent b65d233 commit a92a7ab
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 43 deletions.
9 changes: 0 additions & 9 deletions app/app.iml
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,16 @@
<sourceFolder url="file:https://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file:https://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/debug" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/dex" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/dex-cache" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.0.1/jars" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.0.1/jars" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.0.1/jars" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/jacoco" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/javaResources" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/libs" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/ndk" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/proguard" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file:https://$MODULE_DIR$/build/intermediates/symbols" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import java.util.List;

import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
Expand Down Expand Up @@ -71,9 +72,14 @@ private void init(View view, Bundle savedInstanceState) {
if (recyclerViewAdapter.isAllItemsLoaded()) {
return;
}

// RecyclerView pagination
pagingSubscription = PaginationTool
.paging(recyclerView, offset -> EmulateResponseManager.getInstance().getEmulateResponse(offset, LIMIT), LIMIT)
PaginationTool<List<Item>> paginationTool = PaginationTool.buildPagingObservable(recyclerView, offset -> EmulateResponseManager.getInstance().getEmulateResponse(offset, LIMIT))
.setLimit(LIMIT)
.build();

pagingSubscription = paginationTool
.getPagingObservable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<Item>>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
/**
* @author e.matsyuk
*/
public class PaginationTool {
public class PaginationTool<T> {

// for first start of items loading then on RecyclerView there are not items and no scrolling
private static final int EMPTY_LIST_ITEMS_COUNT = 0;
Expand All @@ -39,35 +39,17 @@ public class PaginationTool {
// default max attempts to retry loading request
private static final int MAX_ATTEMPTS_TO_RETRY_LOADING = 3;

public static <T> Observable<T> paging(RecyclerView recyclerView, PagingListener<T> pagingListener) {
return paging(recyclerView, pagingListener, DEFAULT_LIMIT, EMPTY_LIST_ITEMS_COUNT, MAX_ATTEMPTS_TO_RETRY_LOADING);
}

public static <T> Observable<T> paging(RecyclerView recyclerView, PagingListener<T> pagingListener, int limit) {
return paging(recyclerView, pagingListener, limit, EMPTY_LIST_ITEMS_COUNT, MAX_ATTEMPTS_TO_RETRY_LOADING);
}
private RecyclerView recyclerView;
private PagingListener<T> pagingListener;
private int limit;
private int emptyListCount;
private int retryCount;
private boolean emptyListCountPlusToOffset;

public static <T> Observable<T> paging(RecyclerView recyclerView, PagingListener<T> pagingListener, int limit, int emptyListCount) {
return paging(recyclerView, pagingListener, limit, emptyListCount, MAX_ATTEMPTS_TO_RETRY_LOADING);
private PaginationTool() {
}

public static <T> Observable<T> paging(RecyclerView recyclerView, PagingListener<T> pagingListener, int limit, int emptyListCount, int retryCount) {
if (recyclerView == null) {
throw new PagingException("null recyclerView");
}
if (recyclerView.getAdapter() == null) {
throw new PagingException("null recyclerView adapter");
}
if (limit <= 0) {
throw new PagingException("limit must be greater then 0");
}
if (emptyListCount < 0) {
throw new PagingException("emptyListCount must be not less then 0");
}
if (retryCount < 0) {
throw new PagingException("retryCount must be not less then 0");
}

public Observable<T> getPagingObservable() {
int startNumberOfRetryAttempt = 0;
return getScrollObservable(recyclerView, limit, emptyListCount)
.subscribeOn(AndroidSchedulers.mainThread())
Expand All @@ -76,7 +58,7 @@ public static <T> Observable<T> paging(RecyclerView recyclerView, PagingListener
.switchMap(offset -> getPagingObservable(pagingListener, pagingListener.onNextPage(offset), startNumberOfRetryAttempt, offset, retryCount));
}

private static Observable<Integer> getScrollObservable(RecyclerView recyclerView, int limit, int emptyListCount) {
private Observable<Integer> getScrollObservable(RecyclerView recyclerView, int limit, int emptyListCount) {
return Observable.create(subscriber -> {
final RecyclerView.OnScrollListener sl = new RecyclerView.OnScrollListener() {
@Override
Expand All @@ -85,20 +67,22 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int position = getLastVisibleItemPosition(recyclerView);
int updatePosition = recyclerView.getAdapter().getItemCount() - 1 - (limit / 2);
if (position >= updatePosition) {
subscriber.onNext(recyclerView.getAdapter().getItemCount());
int offset = emptyListCountPlusToOffset ? recyclerView.getAdapter().getItemCount() : recyclerView.getAdapter().getItemCount() - emptyListCount;
subscriber.onNext(offset);
}
}
}
};
recyclerView.addOnScrollListener(sl);
subscriber.add(Subscriptions.create(() -> recyclerView.removeOnScrollListener(sl)));
if (recyclerView.getAdapter().getItemCount() == emptyListCount) {
subscriber.onNext(recyclerView.getAdapter().getItemCount());
int offset = emptyListCountPlusToOffset ? recyclerView.getAdapter().getItemCount() : recyclerView.getAdapter().getItemCount() - emptyListCount;
subscriber.onNext(offset);
}
});
}

private static int getLastVisibleItemPosition(RecyclerView recyclerView) {
private int getLastVisibleItemPosition(RecyclerView recyclerView) {
Class recyclerViewLMClass = recyclerView.getLayoutManager().getClass();
if (recyclerViewLMClass == LinearLayoutManager.class || LinearLayoutManager.class.isAssignableFrom(recyclerViewLMClass)) {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager)recyclerView.getLayoutManager();
Expand All @@ -115,7 +99,7 @@ private static int getLastVisibleItemPosition(RecyclerView recyclerView) {
throw new PagingException("Unknown LayoutManager class: " + recyclerViewLMClass.toString());
}

private static <T> Observable<T> getPagingObservable(PagingListener<T> listener, Observable<T> observable, int numberOfAttemptToRetry, int offset, int retryCount) {
private Observable getPagingObservable(PagingListener<T> listener, Observable<T> observable, int numberOfAttemptToRetry, int offset, int retryCount) {
return observable.onErrorResumeNext(throwable -> {
// retry to load new data portion if error occurred
if (numberOfAttemptToRetry < retryCount) {
Expand All @@ -127,4 +111,73 @@ private static <T> Observable<T> getPagingObservable(PagingListener<T> listener,
});
}

public static <T> Builder<T> buildPagingObservable(RecyclerView recyclerView, PagingListener<T> pagingListener) {
return new Builder<>(recyclerView, pagingListener);
}

public static class Builder<T> {

private RecyclerView recyclerView;
private PagingListener<T> pagingListener;
private int limit = DEFAULT_LIMIT;
private int emptyListCount = EMPTY_LIST_ITEMS_COUNT;
private int retryCount = MAX_ATTEMPTS_TO_RETRY_LOADING;
private boolean emptyListCountPlusToOffset = false;

private Builder(RecyclerView recyclerView, PagingListener<T> pagingListener) {
if (recyclerView == null) {
throw new PagingException("null recyclerView");
}
if (recyclerView.getAdapter() == null) {
throw new PagingException("null recyclerView adapter");
}
if (pagingListener == null) {
throw new PagingException("null pagingListener");
}
this.recyclerView = recyclerView;
this.pagingListener = pagingListener;
}

public Builder<T> setLimit(int limit) {
if (limit <= 0) {
throw new PagingException("limit must be greater then 0");
}
this.limit = limit;
return this;
}

public Builder<T> setEmptyListCount(int emptyListCount) {
if (emptyListCount < 0) {
throw new PagingException("emptyListCount must be not less then 0");
}
this.emptyListCount = emptyListCount;
return this;
}

public Builder<T> setRetryCount(int retryCount) {
if (retryCount < 0) {
throw new PagingException("retryCount must be not less then 0");
}
this.retryCount = retryCount;
return this;
}

public Builder<T> setEmptyListCountPlusToOffset(boolean emptyListCountPlusToOffset) {
this.emptyListCountPlusToOffset = emptyListCountPlusToOffset;
return this;
}

public PaginationTool<T> build() {
PaginationTool<T> paginationTool = new PaginationTool<>();
paginationTool.recyclerView = this.recyclerView;
paginationTool.pagingListener = pagingListener;
paginationTool.limit = limit;
paginationTool.emptyListCount = emptyListCount;
paginationTool.retryCount = retryCount;
paginationTool.emptyListCountPlusToOffset = emptyListCountPlusToOffset;
return paginationTool;
}

}

}

0 comments on commit a92a7ab

Please sign in to comment.