markomilos / paginate Goto Github PK
View Code? Open in Web Editor NEWLibrary for creating simple pagination functionality upon RecyclerView and AbsListView
License: Apache License 2.0
Library for creating simple pagination functionality upon RecyclerView and AbsListView
License: Apache License 2.0
I have setup a repository for this issue.
recyclerView.getAdapter().registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
Toast.makeText(MainActivity.this, "inserted", Toast.LENGTH_SHORT).show();
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
Toast.makeText(MainActivity.this, "removed", Toast.LENGTH_SHORT).show();
}
});
Basically, when using this library, I am not able to receive notification when items in adapter are added using AdapterDataObserver
. onItemRangeRemoved()
and onItemRangeChanged()
are triggered, but not onItemRangeInserted()
.
I assume this is because Paginate has changed the adapter set to the RecyclerView. If so, is there a way to get the actual adapter from Paginate?
Hi Marko
In may case I tried to reattach the pagination after I filter the items in the adapter, so i dont need the pagination since the items are static and depend on the items already exist.
after that, when the user click say all the item the pagination should reattach again.
How to do that.
Thanks for you help
Hello @MarkoMilos,
First of all, thanks a lot for creating such a wonderful API for pagination. It works smooth for me.
But this is having an issue, if invoking onLoadMore() method on activity onCreateView(), REST API is invoking two times. This is happening because of below code:
private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { checkEndOffset(); // Each time when list is scrolled check if end of the list is reached } };
Method RecyclerView.OnScrollListenervoid onScrolled (RecyclerView recyclerView, int dx, int dy):
Source[https://developer.android.com/reference/android/support/v7/widget/RecyclerView.OnScrollListener.html#onScrolled(android.support.v7.widget.RecyclerView, int, int)]
Callback method to be invoked when the RecyclerView has been scrolled. This will be called after the scroll has completed.
This callback will also be called if visible item range changes after a layout calculation. In that case, dx and dy will be 0.
So could you please add some condition to prevent onScrolled() method invocation on view creation.
This will be helpful.
Thanks,
Chandan Kushwaha
Thanks a lot for this great library.I would like to reload to get contents in case there is an error in connection during trial.How possible is that?
My RecyclerViewAdapter used onAttachedToRecyclerView and onDetachedFromRecyclerView Method.
But WrapperAdapter in RecyclerPaginate not called it.
Thanks for your library, it is convenient for me to do pulling-up operations in my app.
However, I found that "onLoadMore" method is passively called in the case where the list which uses Paginate initializes. For example, when the list which is initialized only has two items so that it can not fill the phone screen, the onLoadMore method is invoked strangely. I read your source code, and I found some code in the EndScrollListener.java below:
@Override
public void onScroll(AbsListView view, int firstVisibleItemPosition, int visibleItemCount, int totalItemCount) {
if ((totalItemCount - visibleItemCount) <= (firstVisibleItemPosition + visibleThreshold)) {
callback.onEndReached();
}
if (delegate != null) {
delegate.onScroll(view, firstVisibleItemPosition, visibleItemCount, totalItemCount);
}
}
I found that "onEndReached is called" leads to my question. So I change the code above to this:
@Override
public void onScroll(AbsListView view, int firstVisibleItemPosition, int visibleItemCount, int totalItemCount) {
if (((totalItemCount - visibleItemCount) <= (firstVisibleItemPosition + visibleThreshold)) && (totalItemCount != visibleItemCount)) {
// if (((totalItemCount - visibleItemCount) <= (firstVisibleItemPosition + visibleThreshold))) {
callback.onEndReached();
}
if (delegate != null) {
delegate.onScroll(view, firstVisibleItemPosition, visibleItemCount, totalItemCount);
}
}
I use this condition: totalItemCount != visibleItemCount
It seems my queestion has gone out after my change.
Could you please give some advice on my problem and my change on your code? Is my change on your code correct and is there any more efficient solution to solve my question? Please help and sorry for my poor English.If you are puzzled with my question, I will describe my question more detailedly afterwards.
The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131624135, class android.widget.ListView) with Adapter(class com.paginate.abslistview.WrapperAdapter)]
Hi,
I was not able to access classes since there is no access modifier please add the access modifier
First, thank you for this excellent library !
Well, I have one problem when use it.
How to remove loading row (which is default setup) if no data in the RecyclerView so I can show my EMPTY view fully ?
package com.example.yash.doublerecycle;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.CountDownTimer;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.TextView;
import com.paginate.Paginate;
import com.paginate.recycler.LoadingListItemCreator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
public class MainActivity extends AppCompatActivity {
RecyclerView.Adapter mAdapter2;
ArrayList alImage;
ArrayList aboutchair;
private final int AUTOLOAD_THRESHOLD = 4;
private final int MAXIMUM_ITEMS = 52;
private View mFooterView;
private Handler mHandler;
private boolean mIsLoading = false;
private boolean mMoreDataAvailable = true;
private boolean mWasLoading = false;
private HLVAdapter mAdapter;
ArrayList<String> chairnumber, dimension, hight, diameter, length, volume, introl;
RecyclerView mRecyclerView, mRecyclerView2;
RecyclerView.LayoutManager mLayoutManager, mLayoutManager2;
private static final int GRID_SPAN = 3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar ack = getSupportActionBar();
ack.hide();
alImage = new ArrayList<>(Arrays.asList(R.drawable.h, R.drawable.h, R.drawable.h, R.drawable.h, R.drawable.h, R.drawable.h, R.drawable.h, R.drawable.h, R.drawable.h, R.drawable.h, R.drawable.h, R.drawable.h));
aboutchair = new ArrayList<>(Arrays.asList("gray", "blue", "red", "yellow", "gray", "blue", "red", "yellow", "gray", "blue", "red", "yellow"));
//<---Adapter -->
chairnumber = new ArrayList<>(Arrays.asList("123", "345", "678", "912", "gray", "blue", "red", "yellow", "gray", "blue", "red", "yellow"));
dimension = new ArrayList<>(Arrays.asList("12cm", "12cm", "12cm", "12cm", "gray", "blue", "red", "yellow", "gray", "blue", "red", "yellow"));
introl = new ArrayList<>(Arrays.asList("-", "-", "-", "-", "gray", "blue", "red", "yellow", "gray", "blue", "red", "yellow"));
hight = new ArrayList<>(Arrays.asList("27cm", "27cm", "27cm", "27cm", "gray", "blue", "red", "yellow", "gray", "blue", "red", "yellow"));
diameter = new ArrayList<>(Arrays.asList("N/A", "N/A", "N/A", "N/A", "gray", "blue", "red", "yellow", "gray", "blue", "red", "yellow"));
length = new ArrayList<>(Arrays.asList("N/A", "N/A", "N/A", "912", "gray", "blue", "red", "yellow", "gray", "blue", "red", "yellow"));
volume = new ArrayList<>(Arrays.asList("N/A", "N/A", "N/A", "N/A", "gray", "blue", "red", "yellow", "gray", "blue", "red", "yellow"));
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
mRecyclerView2 = (RecyclerView) findViewById(R.id.recycler_view1);
mRecyclerView2.setHasFixedSize(true);
// The number of Columns
mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
mRecyclerView.setLayoutManager(mLayoutManager);
mLayoutManager2 = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
mRecyclerView2.setLayoutManager(mLayoutManager2);
mAdapter2 = new HLVAdapter2(MainActivity.this, chairnumber, dimension, hight, diameter, length, volume, introl);
mAdapter = new HLVAdapter(MainActivity.this, alImage, aboutchair);
//
mRecyclerView.setAdapter(mAdapter);
mRecyclerView2.setAdapter(mAdapter2);
// mRecyclerView.setAdapter(mAdapter);
Paginate.Callbacks callbacks = new Paginate.Callbacks() {
@Override
public void onLoadMore() {
// Load next page of data (e.g. network or database)
}
@Override
public boolean isLoading() {
// Indicate whether new page loading is in progress or not
return true;
}
@Override
public boolean hasLoadedAllItems() {
// Indicate whether all data (pages) are loaded or not
return true;
}
};
Paginate.with(mRecyclerView, callbacks)
.setLoadingTriggerThreshold(2)
.addLoadingListItem(false)
.setLoadingListItemCreator(HLVAdapter.ViewHolder)
.build();
}
}
--------------------------------------------------my adapter-----------------------------------------
package com.example.yash.doublerecycle;
/**
import com.bumptech.glide.Glide;
import com.paginate.abslistview.LoadingListItemCreator;
import java.util.ArrayList;
public class HLVAdapter extends RecyclerView.Adapter<HLVAdapter.ViewHolder> {
ArrayList alImage;
ArrayList aboutchair ;
Context ctx;
public HLVAdapter(Context context, ArrayList<Integer> alImage,ArrayList<String> aboutchair) {
super();
this.ctx = context;
this.alImage = alImage;
this.aboutchair = aboutchair;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.grid_item, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
viewHolder.imgThumbnail.setImageResource(alImage.get(i));
int image = alImage.get(i);
viewHolder.imgThumbnail.setImageResource(image);
Glide.with(ctx)
.load(image)
.override(150, 150)
.into(viewHolder.imgThumbnail);
viewHolder.aboutchair.setText(aboutchair.get(i));
viewHolder.aboutchair.setTypeface(Validate.setTypeface( ctx ));
viewHolder.setClickListener(new ItemClickListener() {
@Override
public void onClick(View view, int position, boolean isLongClick) {
if (isLongClick) {
Toast.makeText(ctx, "#" + position , Toast.LENGTH_SHORT).show();
ctx.startActivity(new Intent(ctx, MainActivity.class));
} else {
Toast.makeText(ctx, "#" + position , Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
public int getItemCount() {
return alImage.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener{
public ImageView imgThumbnail;
public TextView aboutchair,chairnumber;
private ItemClickListener clickListener;
public ViewHolder(View itemView) {
super(itemView);
imgThumbnail = (ImageView) itemView.findViewById(R.id.img_thumbnail);
aboutchair = (TextView) itemView.findViewById(R.id.productname);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
public void setClickListener(ItemClickListener itemClickListener) {
this.clickListener = itemClickListener;
}
@Override
public void onClick(View view) {
clickListener.onClick(view, getPosition(), false);
}
@Override
public boolean onLongClick(View view) {
clickListener.onClick(view, getPosition(), true);
return true;
}
}
}
Hi Marko
I want to reinitialize the pagination when I return to the top position. And I want to call loadMore items method freshly to load new data. Can you tell me how to do that?
Thanks for a great plugin.
I implement your library but it has not effect but showing only loading view. I debug that it never called on load more method.please help me. below code is paginate declaration..
`private void setScrollListener() {
int threshold=1;
paginate = Paginate.with(listProduct, this)
.addLoadingListItem(true)
.setLoadingTriggerThreshold(threshold)
.setLoadingListItemSpanSizeLookup(new LoadingListItemSpanLookup() {
@Override
public int getSpanSize() {
return newSpanCount;
}
})
.build();
}`
Here is the where i initialize my adapter
`productAdapter = new ProductAdapter(getActivity(), productList);
listProduct.setAdapter(productAdapter);
productAdapter.notifyDataSetChanged();
setScrollListener();`
and there are my callback methods ..
` @Override
public void onLoadMore() {
onLoadMoreCallback();
}
@Override
public boolean isLoading() {
// Indicate whether new page loading is in progress or not
return loading;
}
@Override
public boolean hasLoadedAllItems() {
// Indicate whether all data (pages) are loaded or not
return pageNumber == totalProductpage;
}`
I have the following code and loading row is still showing.
Why?
@Override
public void onLoadMore() {
Log.d("EncryptionPager","onLoadMore");
}
@Override
public boolean isLoading() {
Log.d("EncryptionPager","isLoading");
return false;
}
@Override
public boolean hasLoadedAllItems() {
Log.d("EncryptionPager","hasLoadedAllItems");
return true;
}
I don't know whats going on. I use this library with Paging library (without BoundaryCallback), when the first page is loaded, the recyclerview scrolls to the bottom and continues loading data until it loads all the items in the server.
Thank you for the library.
Is there any available method to forcely close(invisible) the loading list item when cannot get data from server... (for example.. when the server down)
Is there is any way to add support for nested scroll view as well
So, the code will be
Paginate.with(nestedScrollView);
as well as:
Paginate.with(recyclerView);
I want to create different sizes of rows. when i use GridLayoutManager.SpanSizeLookup i can like this:
mGridLayout.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
switch (adapter.getItemViewType(position)) {
case TYPE_PAGE_VIEWER:
return 1;
default:
return 2;
}
}
});
but with the one in your library it does not return position so i cant have different row sizes.
the one in your library looks like this:
setLoadingListItemSpanSizeLookup(new LoadingListItemSpanLookup() {
@Override
public int getSpanSize() {
return 2; //i want to change this dynamically but no position is passed in like googles
}
})
my goal is to have a gridlayout that uses your library but that i can have different size rows . for example first row had 3 items but 5th row can have 5 items. etc.
Hello,
Firstly thanks very much for your work. It has been very easy to get up and running with the library. ๐
I have run into trouble though; I need access to my "WrappedAdapter" for another library. I am testing out libraries for FastScroll w/ RecyclerView and have come across this https://github.com/krimin-killr21/MaterialScrollBar.
The problem is this library requires that the RecyclerView.Adapter must implement an interface (this interface tells the indicator which letter to display at which position). At runtime MaterialScrollBar checks if it does and crashes as your libs Adapter has wrapped mine which has the interface implementation.
My question is would it be possible for your WrappedAdapter class to extend the Adapter it is wrapping. Not sure would this be possible but I believe it would solve my problem. If you think it would work let me know and I can try to implement it and create a pull request.
Or maybe you have another solution?
Thanks in advance!
Hello,
I am using CarouselLayoutManager for my recycle view. I used your library for paginaion.
Its working fine with linear, grid and staggered LayoutManager.
But I need to do pagination on CarouselLayoutManager. As I apply pagination to CarouselLayoutManager its give following exception :
java.lang.IllegalStateException: LayoutManager needs to subclass LinearLayoutManager or StaggeredGridLayoutManager at com.paginate.recycler.RecyclerPaginate.checkEndOffset(RecyclerPaginate.java:91) at com.paginate.recycler.RecyclerPaginate.(RecyclerPaginate.java:50) at com.paginate.recycler.RecyclerPaginate$Builder.build(RecyclerPaginate.java:241)
Thanks
Perhaps update the readme with a Proguard FAQ or something
I am facing an issue in pagination,
I want to restrict my paginate object not to call automatically when I attach it to My RecyclerView is there anything I am missing please let me know.
Thanks
Is there support from stack end recyclerview?
Hello, Thanks for your helpful library.
Is there any way to handle network or other errors while loading next page?. Like retry button in order to load again the same page. How can handle this situvation.
I am thinking about using this project after I readed README.md.
Please tell me what's the meaning of "Paginate.setLoadingTriggerThreshold(2)"?
Hello, Marko. Thank you very much for the great lib. It's working great for me and you save me a lot of time and effort. I have two fragments. In the first one I have a recycle view only and I use Paginate and it works just great. In the second fragment I have a Nested scroll view like this:
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/profileBg">
<android.support.v7.widget.RecyclerView android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
android:background="@color/profileBg"
xmlns:android="http://schemas.android.com/apk/res/android" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
-------------------------------------------------------------------------------------------
LinearLayoutManager layoutManager = new LinearLayoutManager(mContext);
layoutManager.setAutoMeasureEnabled(true);
adapter = new PostAdapter(mContext, posts, this);
list.setLayoutManager(layoutManager);
list.setNestedScrollingEnabled(false);
list.addItemDecoration(new SpacesItemDecoration((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, mContext.getResources().getDisplayMetrics())));
list.setAdapter(adapter);
callbacks = new Paginate.Callbacks() {
@Override
public void onLoadMore() {
loading = true;
OFFSET += LIMIT;
loadNextDataFromApi(OFFSET);
}
@Override
public boolean isLoading() {
return loading;
}
@Override
public boolean hasLoadedAllItems() {
return false;
}
};
paginate = Paginate.with(list, callbacks)
.setLoadingTriggerThreshold(8)
.build();
I also tried without:
layoutManager.setAutoMeasureEnabled(true);
list.setNestedScrollingEnabled(false);
but the result is the same. I use the same logic in the two places but when it's in the nested scroll view scrolling becomes really slow and finally app just stop working. Without the Paginate it's work fine. Do you have any suggestions for this bug? Thank you very much!
Update: I set a break point and found that with NestedScrollView it enters in the callback infinity times even without scrolling. I hope this can help you finding the problem.
Update 2: The same problem when embedded in a CordinatorLayout.
` public void onLoadMore() {
Log.d("p", "onLoadMore()");
reqExp();
loading = true;
}`
@Override public boolean isLoading() { Log.d("p", "isLoading()"); return loading; }
in my response from network
mUserLst = UserParse.Data(mResponse); mAdopter.add(mUserLst); loading = false;
my problem is that when activity start on load more called two times. i dont understand
Paginate.with(mRv,this) .setLoadingTriggerThreshold(2) .addLoadingListItem(true) .setLoadingListItemCreator(new CustomLoadingListItemCreator()) .build();
onloadmore method is called even if its not end of page, I would like to understand in what condition onloadmore will be called
Thanks!
Upon scrolling to end I am getting this error
Hello, was wondering how it's possible to achieve the downward animation of the progress bar when loading is complete as it simply disappears for me (without any animation). Thanks.
Hi there, great library!
I was wondering about this exception that keeps happening at certain times where the paginate object was unbound and now you call unbind on it again:
Fatal Exception: java.lang.IllegalStateException
Observer com.paginate.a.g@6489523 was not registered.
com.paginate.recycler.RecyclerPaginate.unbind
I know that the simple solution is to not do this, but do you know how I can find if paginate has been registered first before i call that unbind()
?
Thanks a lot
Hello! Thx for great library!
I found one strange feature, looks like error; when we make unbind, we take original adapter and cast it to BaseAdapter, but in case when it was custom adapter with different type and additional features, we discount it's type and features. I think we should get adapter type via reflection or generic type and return adapter with proper type as it was before. Thx!
@OverRide
public void unbind() {
// Swap back original scroll listener
absListView.setOnScrollListener(scrollListener.getDelegateScrollListener());
// Swap back source adapter
if (absListView.getAdapter() instanceof WrapperAdapter) {
WrapperAdapter wrapperAdapter = (WrapperAdapter) absListView.getAdapter();
BaseAdapter adapter = (BaseAdapter !!!!! we should somehow get real adapter type here (via reflection, or generic type, otherwise we can loose type features)) wrapperAdapter.getWrappedAdapter();
adapter.unregisterDataSetObserver(dataSetObserver);
((AdapterView) absListView).setAdapter(adapter);
}
}
Hello, thanks for your helpful library, anyway I have some problem when i implemented swipe refresh layout with your library. My code is that when refresh call back execute, I request to REST API to retrieve data as Pagination, but recyclerview not scroll to first item. Do you have any idea about it ?
if list is empty and i add the manually item in list and notify the adapter so pagination call and list will show double item
I'm using a RecyclerView with GridLayoutManager to create a two-columns grid. After adding Paginate to my project the first row started to be displayed merged.
How can I disable this?
Hi @MarkoMilos ,
I am using you pagination librarie but one question come to my mind when revieing the sample source code.
Let's say that for example we have 1milion records that needs to be scrolled and we load 100items per page, shouldn't we keep a buffer of 100 elements per page only inside the adapter and when going to the next page to load the first 100 items and remove the items that are not visible currently on screen.
(Lets assume that the data we posses is infinite and at some point in time the device will return OOM exception if we only add data to the recycleView adapter)
So when we scroll down increase page by one add 100 elements.
When returning by scrolling up decrease page by one and add 100 elements on top of the adapter data structure.
Can you put some light here, thanks :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.