I have a problem with RecyclerView. I implemented OnScrollListener to it and when user reach end of list it should load a new data depending on index (index 1 loading first 8 index 2 loading second 8 etc) But problem is as soon as adapter start loading new data it scroll me to top :(
This is my code from function where I'm calling server:
public void showlist() {
progressBar = new ProgressDialog(getActivity());
progressBar.setMessage("Please wait ...");
progressBar.show();
NetworkSDK.getInstance().getNews(size, offset, new Callback<List<News>>() {
#Override
public void onResponse(Call<List<News>> call, Response<List<News>> response) {
if (response.code() == 401) {
Intent intent = new Intent(getContext(), MainPreLogin.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
progressBar.dismiss();
startActivity(intent);
SharedData.getInstance().removeString("token");
}
if (response.isSuccess()) {
newsAdapter = new NewsAdapterRecycler(listNews);
if (response.body().size() == 0) {
progressBar.dismiss();
Toast.makeText(getActivity(), R.string.noMorenews, Toast.LENGTH_SHORT).show();
} else {
for (int i = 0; i < response.body().size(); i++) {
newsAdapter.insert(newsAdapter.getItemCount() + 1, response.body().get(i));
}
newsList.setAdapter(newsAdapter);
newsAdapter.notifyDataSetChanged();
progressBar.dismiss();
}
}
}
#Override
public void onFailure(Call<List<ba.project.models.News>> call, Throwable t) {
Toast.makeText(getContext(), R.string.errorNoconnection, Toast.LENGTH_LONG).show();
progressBar.dismiss();
}
});
}
This is my adapter:
public class NewsAdapterRecycler extends RecyclerView.Adapter<NewsAdapterRecycler.MyViewHolder> {
private static int selectedItem = -1;
ArrayList<News> newslist;
Context context;
public NewsAdapterRecycler(ArrayList<News> newslist) {
this.newslist = newslist;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
context = parent.getContext();
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.single_news_layout, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
View view = null;
Log.d("Pozicija News",String.valueOf(position));
News news = newslist.get(position);
holder.shortText.setText(news.getIntro());
holder.name.setText(news.getSubject());
if (news.getImagePath().equals(""))
Picasso.with(context).load(R.drawable.logo_Def).fit().centerCrop().into(holder.picture);
else
Picasso.with(context).load(news.getImagePath()).fit().centerCrop().into(holder.picture);
holder.date.setText(news.getShortDate());
if (selectedItem == position)
holder.itemView.setSelected(true);
}
#Override
public int getItemCount() {
return newslist.size();
}
public void insert(int position, News data) {
newslist.add(position - 1, data);
notifyItemInserted(position);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView name;
TextView shortText;
TextView date;
ImageView picture;
public MyViewHolder(View view) {
super(view);
this.name=(TextView)view.findViewById(R.id.news_title);
this.shortText=(TextView)view.findViewById(R.id.news_desc);
this.picture=(ImageView)view.findViewById(R.id.news_image);
this.date=(TextView)view.findViewById(R.id.news_date);
}
}
}
This is my scrolllsitener
newsList.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = newsList.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
Log.d("Visibleitem", String.valueOf(visibleItemCount));
Log.d("totalItem", String.valueOf(totalItemCount));
Log.d("firstvisibleitem", String.valueOf(firstVisibleItem));
if (restarting) {
previousTotal = 0;
visibleThreshold = 5;
}
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
offset++;
showlist();
// Do something
loading = true;
restarting = false;
}
}
});
Also if it's meter this funciton is called every time when user scroll to this fragment via this:
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser && !areNewsLoaded) {
listNews = new ArrayList<>();
offset=0;
showlist();
restarting = true;
}
}
I tried solutions posted above but none worked. Helpfully I manage to find some fix. Solution is in 3 magic lines :
private Parcelable recyclerViewState;
recyclerViewState = newsList.getLayoutManager().onSaveInstanceState();
newsList.getLayoutManager().onRestoreInstanceState(recyclerViewState);
So basically I added 2. line before adding new content to my list and I guess it remember current position and I added 3. line after adding content so I assume this piece of code remember position
Try using notifyDataSetChanged() instead of notifyItemInserted().
A new insert method:
public void insert(News data) {
newslist.add(data);
notifyDataSetChanged();
}
Also i suggest create method to append all news at one time and use addAll method of ArrayList
try something like this ,
first you have to create interface
public interface Update{
public void OnDBUpdate();
}
then in Main Activity or somewhere add this
public class MainActivity extends AppCompatActivity implements DialogFragUpdateListener
and create method where you call the Recycler adapter
public void OnDBUpdate() {
dbList =helpher.getDataFromDB();
mAdapter = new RecyclerAdapter(this,dbList);
mRecyclerView.setAdapter(mAdapter);
}
and the last step ,, call the method where you need to update recycler
((Update) getActivity()).OnDBUpdate();
hope this help :)
Related
I have Recycler view in Android and I need to implement load more at recycler view, I searched over internet but failed to solve my problem, this is my code please help
This is the adapter
public class NewsReycelerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
List<String> Dates , Titles , Details , Images;
public static String NewsDetail,NewsDate ,NewsTitle;
public final int TYPE_NEWS = 0;
public final int TYPE_LOAD = 1;
private int visibleThreshold = 2;
private int lastVisibleItem, totalItemCount;
private boolean loading;
private OnLoadMoreListener onLoadMoreListener;
public NewsReycelerViewAdapter(RecyclerView recyclerView,Context context , List<String> stringsDate , List<String> stringTitles , List<String> stringDetails ,List<String> stringImage,final JPANewsFragment fragment) {
this.context = context;
this.Dates = stringsDate;
this.Titles = stringTitles;
this.Details = stringDetails;
this.Images = stringImage;
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
if (onLoadMoreListener != null) {
onLoadMoreListener.onLoadMore();
}
fragment.getHtmlNewsData("1");
loading = true;
}
}
});
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType==TYPE_NEWS){
return new Item_Holder(inflater.inflate(R.layout.news_adapter_item,parent,false));
}else{
return new LoadHolder(inflater.inflate(R.layout.item_loading,parent,false));
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((Item_Holder)holder).Date.setText(Dates.get(position));
((Item_Holder)holder).Title.setText(Titles.get(position));
NewsDetail = Details.get(position);
NewsDate = Dates.get(position);
NewsTitle = Titles.get(position);
((Item_Holder)holder).itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((MainActivity)context).changeFragmentMethod(new NewsDetailsFragment(),context.getResources().getString(R.string.news_details));
}
});
}
#Override
public int getItemCount() {
return Dates == null ? 0 : Dates.size();
}
//////////////////////////////////////////////////////////////////////////////////
public class Item_Holder extends RecyclerView.ViewHolder {
TextView Title , Date ;
ImageView jpaThumbnail;
public Item_Holder(View itemView) {
super(itemView);
Title = (TextView) itemView.findViewById(R.id.textView_title);
Date = (TextView) itemView.findViewById(R.id.textView_date);
jpaThumbnail = (ImageView) itemView.findViewById(R.id.thumbnail);
}
}
static class LoadHolder extends RecyclerView.ViewHolder{
public LoadHolder(View itemView) {
super(itemView);
}
}
#Override
public int getItemViewType(int position) {
return Dates.get(position) != null ? TYPE_NEWS : TYPE_LOAD;
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.onLoadMoreListener = mOnLoadMoreListener;
}
public void setLoaded() {
loading = false;
}
}
First api have 10 item and when user swipes, I need to load more from another page,
and this is the code written in my main activity
newsReycelerViewAdapter = new NewsReycelerViewAdapter(recyclerViewNews,context, stringsDate, stringsTitle, stringsDetails,stringsImages,new JPANewsFragment());
recyclerViewNews.setLayoutManager(new LinearLayoutManager(context));
recyclerViewNews.setAdapter(newsReycelerViewAdapter);
loadingProgressBar.setVisibility(View.GONE);
newsReycelerViewAdapter.setLoaded();
newsReycelerViewAdapter.notifyDataSetChanged();
Please let me know how to solve this issue.
First add a addOnScrollListener() for your RecyclerView and detect scroll down
recyclerViewNews.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) {
Log.e("test","reached the last element of recyclerview");
visibleItemCount = mLinearLayoutManager.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
pastVisiblesItems = mLinearLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
loading = false;
fetchData();
}
}
}
}
});
Second Create a function fetchData() to add more data to your adapter
then call on newsReycelerViewAdapter.notifyDataSetChanged(); to notify the dataset change and change loading=true
On your activity main create fields as
int pastVisiblesItems, visibleItemCount, totalItemCount;
boolean loading = true;
Here is example for Simple Implementation of LoadMore RecyclerView using a Simple Library compiled from the various sources.
Add this line in build.gradle
implementation 'com.hereshem.lib:awesomelib:2.0.1'
Create RecyclerView Layout in Activity with
<com.hereshem.lib.recycler.MyRecyclerView
android:id="#+id/recycler"
app:layoutManager="LinearLayoutManager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Create a ViewHolder by passing the class that supports
public static class EVHolder extends MyViewHolder<Events> {
TextView date, title, summary;
public EVHolder(View v) {
super(v);
date = v.findViewById(R.id.date);
title = v.findViewById(R.id.title);
summary = v.findViewById(R.id.summary);
}
#Override
public void bindView(Events c) {
date.setText(c.date);
title.setText(c.title);
summary.setText(c.summary);
}
}
Create Items List variable and adapters with very few lines by passing items, class and layout in the adapter
List<Events> items = new ArrayList<>();
MyRecyclerView recycler = findViewById(R.id.recycler);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, items, EVHolder.class, R.layout.row_event);
recycler.setAdapter(adapter);
ClickListener and LoadMore Listener can be added with following lines
recycler.setOnItemClickListener(new MyRecyclerView.OnItemClickListener() {
#Override
public void onItemClick(int position) {
Toast.makeText(MainActivity.this, "Recycler Item Clicked " + position, Toast.LENGTH_SHORT).show();
}
});
recycler.setOnLoadMoreListener(new MyRecyclerView.OnLoadMoreListener() {
#Override
public void onLoadMore() {
loadData();
}
});
loadData();
After the data is loaded this must be called
recycler.loadComplete();
When no LoadMore is required LoadMore layout can be hidden by calling
recycler.hideLoadMore();
Complete example can be found here
Hope this helps :)
My loadmore function looks like:
private void loadMoreMessages() {
DatabaseReference messageRef = mRootRef.child("messages").child(mThemaID);
Query messageQuery = messageRef.orderByKey().endAt(mLastKey).limitToLast(10);
messageQuery.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Messages message = dataSnapshot.getValue(Messages.class);
String messageKey = dataSnapshot.getKey();
if(!mPrevKey.equals(messageKey)){
messagesList.add(itemPos++, message);
}else {
mPrevKey = mLastKey;
}
if(itemPos == 1){
mLastKey = messageKey;
}
mAdapter.notifyDataSetChanged();
mLinearLayout.scrollToPositionWithOffset(itemPos-1, 0);
mRefreshLayout.setRefreshing(false);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
and the listener:
mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
mCurrentPage++;
itemPos = 0;
loadMoreMessages();
}
});
maybe you can do something with this
Needless to say, I came across a lot of proposed solutions for this particular problem. I removed scrollListener and implemented it inside my fragment, I used notifyItemRangeInserted instead of notifyDataSetChanged. The thing is, none of those solutions did work for me...I'm displaying a set of youtube videos in my app. My dataset is indeed updated; thing is when I scroll downwards, at some point the scroll position moves to the top i.e the very first item of my dataset Here's a snippet of my activity :
private void setUpRecyclerView()
{
mRecyclerView.setHasFixedSize(true);
linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(linearLayoutManager);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold))
{
loadMorePosts();
loading = true;
}
}
});
initAdapter();
}
private void initAdapter()
{
adapter = new MyAdapter(mDataSet, getActivity());
mRecyclerView.setAdapter(adapter);
skeletonScreen = Skeleton.bind(mRecyclerView)
.adapter(adapter)
.shimmer(true)
.angle(30)
.duration(1200)
.count(10)
.load(R.layout.youtube_item)
.show();
}
private void loadVideos(final OnLoadPlayListCallback videosCallback, String pageToken)
{
Call<FullChannelPlayListData> mcallPlayList = mYouTubeService.getPlayList(
Tags.VALUE_SNIPPET,
20,
mPlayListId,
getActivity().getResources().getString(R.string.youtube_data_api_key),
pageToken
);
mcallPlayList.enqueue(new Callback<FullChannelPlayListData>() {
#Override
public void onResponse(Call<FullChannelPlayListData> call, Response<FullChannelPlayListData> response) {
if (response.code() == 200)
{
Log.d("FullPlayListSuccessful", response.message());
videosCallback.onSuccessfulRequest(response.body());
}
else Log.d("FullPlayListUnsuccess", response.message());
}
#Override
public void onFailure(Call<FullChannelPlayListData> call, Throwable t) {
videosCallback.onFailureRequest(t);
}
});
}
#Override
public void onSuccessfulRequest(FullChannelPlayListData fullChannelPlayListData)
{
Log.d(TAG, "onSuccessfulRequest Item size = "+ fullChannelPlayListData.getItems().size());
if (StringUtils.isNotEmpty(mNextPageToken))
removeFooter();
for (FullPlayListItems mItem: fullChannelPlayListData.getItems())
{
FullPlayListItems randomItem = getVideoFromDataSet(mItem.getSnippet().getResourceId().getVideoId(), mDataSet);
if (randomItem == null) {
mDataSet.add(mItem);
}
}
adapter.notifyItemRangeInserted(adapter.getItemCount(), mDataSet.size());
mRecyclerView.postDelayed(new Runnable() {
#Override
public void run() {
skeletonScreen.hide();
}
}, 2000);
mNextPageToken = fullChannelPlayListData.getNextPageToken();
setLoaded();
}
public void setLoaded() {
loading = false;
}
I could use really use some help...
UPDATE MyAdapter class
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
{
private List<FullPlayListItems> mDataSet;
private Context mActivity;
private static final int YOUTUBE_ITEM_VIEW_TYPE = 0;
private static final int PROGRESS_BAR_ITEM_VIEW_TYPE = 1;
public MyAdapter(List<FullPlayListItems> mDataSet, Context mActivity) {
this.mDataSet = mDataSet;
this.mActivity = mActivity;
}
public class ProgressViewHolder extends RecyclerView.ViewHolder
{
#BindView(R.id.pBarLoadMorePosts)
ProgressBar pBarLoadMore;
public ProgressViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
#Override
public int getItemViewType(int position) {
return mDataSet.get(position) != null ? YOUTUBE_ITEM_VIEW_TYPE : PROGRESS_BAR_ITEM_VIEW_TYPE;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
RecyclerView.ViewHolder viewHolder;
if (viewType == PROGRESS_BAR_ITEM_VIEW_TYPE)
{
View pBarLayoutView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.footer_loader, parent, false);
viewHolder = new ProgressViewHolder(pBarLayoutView);
}
else
{
View postItemLayoutView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.youtube_item, parent, false);
viewHolder = new YoutubeItemViewHolder(postItemLayoutView);
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
int viewType = getItemViewType(position);
FullPlayListItems mVideoItem = mDataSet.get(position);
switch (viewType)
{
case PROGRESS_BAR_ITEM_VIEW_TYPE:
ProgressViewHolder progressViewHolder = (ProgressViewHolder) holder;
progressViewHolder.pBarLoadMore.getIndeterminateDrawable().setColorFilter(CoreApplication.getRes().getColor(R.color.colorPrimary), PorterDuff.Mode.SRC_IN);
break;
case YOUTUBE_ITEM_VIEW_TYPE:
default:
YoutubeItemViewHolder youtubeItemViewHolder = (YoutubeItemViewHolder) holder;
youtubeItemViewHolder.mVideoTitle.setText(mVideoItem.getSnippet().getTitle());
youtubeItemViewHolder.sdvYoutubeThumbnail.setImageURI(Uri.parse(mVideoItem.getSnippet().getThumbnails().getHigh().getUrl()));
}
}
#Override
public int getItemCount() {
return mDataSet != null ? mDataSet.size() : 0;
}
public class YoutubeItemViewHolder extends RecyclerView.ViewHolder
{
TextView mVideoTitle;
SimpleDraweeView sdvYoutubeThumbnail;
public YoutubeItemViewHolder(View itemView)
{
super(itemView);
mVideoTitle = (TextView)itemView.findViewById(R.id.tv_video_title);
sdvYoutubeThumbnail = (SimpleDraweeView)itemView.findViewById(R.id.sdv_thumbnail);
}
}
}
And here is my onViewCreated:
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mPlayListId = getArguments().getString(Tags.YT_CHANNEL_PLAYLIST_ID);
setUpRecyclerView();
// Like I said initially mNextPageToken is empty
loadVideos(this, mNextPageToken);
}
Just notify the data change in the onSuccessfulRequest() method.
adapter.notifyDataSetChanged();
I don't know this answer is helpful to you. anyway please try,
Add this method to your MyAdapter
public void addItem(VideoSectionsActivity item){
mDataSet.add(item);
notifyItemInserted(mDataSet.size() - 1);
}
And change your onSuccessfulRequest()
#Override
public void onSuccessfulRequest(FullChannelPlayListData fullChannelPlayListData)
{
Log.d(TAG, "onSuccessfulRequest Item size = "+ fullChannelPlayListData.getItems().size());
if (StringUtils.isNotEmpty(mNextPageToken))
removeFooter();
for (FullPlayListItems mItem: fullChannelPlayListData.getItems())
{
FullPlayListItems randomItem = getVideoFromDataSet(mItem.getSnippet().getResourceId().getVideoId(), mDataSet);
if (randomItem == null) {
adapter.addItem(mItem);
}
}
mRecyclerView.postDelayed(new Runnable() {
#Override
public void run() {
skeletonScreen.hide();
}
}, 2000);
mNextPageToken = fullChannelPlayListData.getNextPageToken();
setLoaded();
}
Updated
And also rearrange your code in activity
private void setUpRecyclerView()
{
mRecyclerView.setHasFixedSize(true);
linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(linearLayoutManager);
initAdapter();
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold))
{
loadMorePosts();
loading = true;
}
}
});
}
I have an internal-database(SQLite) with many entries. So I decided to load the first 20 entries in the listview when the user starts the activity and when he scrolls down he can load 20 more each time pressing a button if there are entries left.
EDIT
//onCreate()
acceptedLogs = helper.getLogsRange(0, LOAD_AMOUNT);
loadedEntriesCounter = LOAD_AMOUNT;
logAdapter = new LogAdapter(acceptedLogs);
logRecyclerView.setAdapter(logAdapter);
logRecyclerView.setHasFixedSize(false);
linearLayoutManager = new LinearLayoutManager(getContext());
logRecyclerView.setLayoutManager(linearLayoutManager);
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = logRecyclerView.getChildCount();
totalItemCount = logRecyclerView.getLayoutManager().getItemCount();
int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
if (loading) { // boolean set to true if you are already loading and false after you will update adaptor
if (totalItemCount > previousTotalCount) {
previousTotalCount = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItemPosition + VISIBLE_THRESHOLD)) {
loading = true;
List<Log> newLogs = helper.getLogsRange(loadedEntriesCounter, LOAD_AMOUNT);
loadedEntriesCounter += LOAD_AMOUNT;
logAdapter.logs.addAll(newLogs);
logAdapter.notifyDataSetChanged();
}
}
The loading only happens ones! Where do I have to set loading on false?
First, better use RecyclerView with viewholder, second you better load data on scroll listener and some trick, for example you have loaded 20 items then when you scroll list there will be good to load data when you scroll list and you scrolled to for example to 18 item at bottom, here you start your async task and when you scroll to 20 your loading will finish and you will update list with 20 more so user will not even see when you are loading.
mVisibleThreshold = 2 // this is count items to bottom of current list when load will start.
here is my on scroll listener for recyclerview (can be adjusted to your listview):
mProductsResultsList.setOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
mVisibleItemCount = mProductsResultsList.getChildCount();
mTotalItemCount = mProductsResultsLayoutManager.getItemCount();
mFirstVisibleItem = mProductsResultsLayoutManager.findFirstVisibleItemPosition();
if (mLoadingInProgress) { // boolean set to true if you are already loading and false after you will update adaptor
if (mTotalItemCount > mPreviousTotal) {
mPreviousTotal = mTotalItemCount;
}
}
if (!mLoadingInProgress && (mTotalItemCount - mVisibleItemCount)
<= (mFirstVisibleItem + mVisibleThreshold)) {
mLoadingInProgress = true;
mLastPageRequest++; // current page to load and add
// Here you load data and update adapter
// if in async task then start it here and set mLoadingInProgress to true and onPostExecute add to list result and make notifyDatasetChanged on adapter then mLoadingInProgress to false.
}
}
});
One more: don't touch any views in background tasks (otherwise you will stuck main thread), make all updates and notifications after task code in onPostExecute with RunOnUIThread.
okay as you are interested in this solution will improve answer:
mLastPageRequest - int I use to know which page I was loaded and which i must load next it's incrementing each time by 1 with ++
after loading data (from database or from web request you should add downloaded items to your list).
Currently in my project my list is "mCategoryProducts" and this is my adapter mProductsResultsListAdapter.
all U need is to add all next items you downloaded to list you attached to adapter with
mCategoryProducts.addAll(downloadedListProducts); // here you are adding items you just loaded to existing list to the end,
now next code:
public void displayGotResults(){
if(mCategoryProducts != null){
if(mProductsResultsListAdapter == null && mLastPageRequest==1){
mProductsResultsListAdapter = new ProductListRecyclerViewAdapter(this, mCategoryProducts, true);
mProductsResultsList.setAdapter(mProductsResultsListAdapter);
mProductsResultsListAdapter.setClickListener(this);
}else{
mProductsResultsListAdapter.notifyDataSetChanged();
//notifyItemInserted(mSearchList.size()-1);
}
if(mCategoryProducts.size()>0) {
mCategoryIsEmptyInfo.setVisibility(View.GONE);
}else{
mCategoryIsEmptyInfo.setVisibility(View.VISIBLE);
}
}else{
mCategoryIsEmptyInfo.setVisibility(View.VISIBLE);
}
}
Here if adapter not already initialised then we create it and attaching to it our list mCategoryProducts otherwise if this is second loading then we simple notify adapter that "Hey man new data is comming :)" with:
mProductsResultsListAdapter.notifyDataSetChanged();
Notes: mCategoryIsEmptyInfo - is view which i show when there is no items to display.
Here you are my custom adaptor with interface for clicks that can be handled in activity )
public class ProductListRecyclerViewAdapter extends RecyclerView.Adapter<ProductListRecyclerViewAdapter.ProductListRecyclerViewHolder> {
private LayoutInflater mInflater;
private Context mContext;
private DrawerLayout mNavigationDrawer;
private ClickListener mClickListener;
private LongClickListener mLongClickListener;
List<ProductModel> navigationData = Collections.emptyList();
private ImageLoader mImageLoader;
private VolleyServiceSingleton mVollayService;
private boolean mShowThumbNail;
//For animations
private int mLastPositiion = -1;
public ProductListRecyclerViewAdapter (Context context, List<ProductModel> navData, boolean showThumbNail){
mInflater = LayoutInflater.from(context);
this.navigationData = navData;
mContext = context;
mVollayService = VolleyServiceSingleton.getInstance();
mImageLoader = mVollayService.getImageLoader();
mShowThumbNail = showThumbNail;
}
#Override
public ProductListRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.list_item_product, parent, false);
ProductListRecyclerViewHolder holder = new ProductListRecyclerViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(final ProductListRecyclerViewHolder viewHolder, int position) {
ProductModel currentItem = navigationData.get(position);
viewHolder.productBrand.setText(currentItem.ManufacturerName);
viewHolder.productName.setText(currentItem.Name);
viewHolder.productCode.setText(currentItem.Code);
viewHolder.productPrice.setText(String.format(mContext.getString(R.string.money_sign), Utils.decimalWithCommas(String.valueOf(currentItem.DealerPrice))));
if(Constants.SHOW_IMAGE_THUMBNAILS_IN_LIST && mShowThumbNail){
if(currentItem.CatalogImage != null && currentItem.CatalogImage.contains("http")){
viewHolder.productThumbnail.setVisibility(View.VISIBLE);
mImageLoader.get(currentItem.CatalogImage, new ImageLoader.ImageListener() {
#Override
public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
viewHolder.productThumbnail.setImageBitmap(response.getBitmap());
}
#Override
public void onErrorResponse(VolleyError error) {
}
});
}
}else{
viewHolder.productThumbnail.setVisibility(View.GONE);
}
}
public void setAnimation(View viewToAnimate, int position)
{
// If the bound view wasn't previously displayed on screen, it's animated
if (position > mLastPositiion)
{
Animation animation = AnimationUtils.loadAnimation(mContext, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
mLastPositiion = position;
}
}
#Override
public int getItemCount() {
return navigationData.size();
}
public void setClickListener(ClickListener clickListener){
this.mClickListener = clickListener;
}
public void setLongClickListener(LongClickListener lognClickListener){
this.mLongClickListener = lognClickListener;
}
public class ProductListRecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener{
TextView productBrand;
TextView productName;
TextView productCode;
TextView productPrice;
ImageView productThumbnail;
public ProductListRecyclerViewHolder(View itemView) {
super(itemView);
productBrand = (TextView) itemView.findViewById(R.id.product_brand);
productName = (TextView) itemView.findViewById(R.id.product_name);
productCode = (TextView) itemView.findViewById(R.id.product_code);
productPrice = (TextView) itemView.findViewById(R.id.product_price);
productThumbnail = (ImageView) itemView.findViewById(R.id.product_thumbnail);
itemView.setOnClickListener(this);
itemView.setTag(this);
itemView.setOnLongClickListener(this);
}
#Override
public void onClick(View v) {
if(mClickListener!=null){
mClickListener.itemClicked(v, getAdapterPosition());
}
}
#Override
public boolean onLongClick(View v) {
if(mLongClickListener!=null){
mLongClickListener.itemLongClicked(v, getAdapterPosition());
}
return false;
}
}
public interface ClickListener{
void itemClicked(View view, int position);
}
public interface LongClickListener{
void itemLongClicked(View view, int position);
}
}
it will probably not work without you update to your needs, but nice sample how must be )
Make attention on
mProductsResultsListAdapter.setClickListener(this);
then in activity you can catch clicks with :
public class ProductListActivity extends ActionBarActivity implements ProductListRecyclerViewAdapter.ClickListener {
//.....
#Override
public void itemClicked(View view, int position) {
}
//.....
}
One more thing if you need to catch click for example on specific view in item in list for example on image in view holder then set click listener to "this" and set tag to this view and in activity then you can get tag from view and you will know where you clicked :)
your loading is from database:
loading = true;
List<Log> newLogs = helper.getLogsRange(loadedEntriesCounter, LOAD_AMOUNT);
loadedEntriesCounter += LOAD_AMOUNT;
logAdapter.logs.addAll(newLogs);
loading = false; // somewhere here
but this is not finally correct way to load data you can stuck main thread coz if database will be too big or you will make "heavy" selection you can get stuck for several milisec. you must do all data loading in async tasks and then on task done notify adapter.
in my project i load data from webapi, not from database but in anyway must be done in same way via async task, this is proper way )
class LoadNextPageTask extends AsyncTask<Integer, Void, List<ProductModel>> {
int pageToLoad;
public LoadNextPageTask(int pageToLoad){
this.pageToLoad = pageToLoad;
}
#Override
protected List<ProductModel> doInBackground(Integer... params) {
return helper.getLogsRange(loadedEntriesCounter, LOAD_AMOUNT); // here apply page to load??? not sure
}
#Override
protected void onPreExecute() {
mMainLoadingProgress.setVisibility(View.VISIBLE);
loading = true;
}
#Override
protected void onPostExecute(List<ProductModel> newLogs) {
loading = false;
loadedEntriesCounter += LOAD_AMOUNT;
logAdapter.logs.addAll(newLogs);
runOnUiThread(new Runnable() {
#Override
public void run() {
logAdapter.notifyDataSetChanged();
}
});
mMainLoadingProgress.setVisibility(View.GONE);
}
}
above is async task please update to your needs
then where data loading simple start it with:
new LoadNextPageTask(pagenumber).execute(); // page is int
Hey community I want to make a RecyclerView like in the chat applications.
I tried setStackFromEnd and it's working good.
final LinearLayoutManager llm = new LinearLayoutManager(getApplicationContext());
llm.setOrientation(LinearLayoutManager.VERTICAL);
llm.setStackFromEnd(true);
My on load more code based on this tutorial, At the end of tutorial you should see a video : Recyclerview Bottom Progress
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
isLoading = true;
}
}
});
So I need to make a RecyclerView like in chat applications. Stack from end is working perfect but I need to trigger load more method when I go top instead of going bottom. Also add new items on top instead of bottom. Thanks in advance.
You don't need to make use of onScrollListener, if you simply want to show a Button "Load Earlier Messages" at the top. You can simply create an xml for your load more Button, make that as the first row of your RecyclerView and create an Interface to handle click events. I am posting code for the Adpater from one of my projects. Hope that will help you in getting some idea to proceed further.
/**
* Created by Mukesh on 21/12/2015.
*/
public class ChatListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private List<UserMessage> userMessagesList;
private LayoutInflater mLayoutInflater;
private static final int ROW_TYPE_LOAD_EARLIER_MESSAGES = 0;
private static final int ROW_TYPE_SENDER = 1;
private static final int ROW_TYPE_RECEIVER = 2;
private int userId;
private boolean isLoadEarlierMsgs;
private LoadEarlierMessages mLoadEarlierMessages;
public ChatListAdapter(Context context, int userId, List<UserMessage> userMessagesList) {
mContext = context;
this.userMessagesList = userMessagesList;
mLayoutInflater = LayoutInflater.from(mContext);
this.userId = userId;
mLoadEarlierMessages = (LoadEarlierMessages) mContext;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case ROW_TYPE_LOAD_EARLIER_MESSAGES:
return new LoadEarlierMsgsViewHolder(mLayoutInflater.inflate(R.layout
.row_load_earlier_messages, parent, false));
case ROW_TYPE_SENDER:
return new SenderMsgViewHolder(mLayoutInflater.inflate(R.layout.row_sender_msg,
parent, false));
case ROW_TYPE_RECEIVER:
return new ReceiverMsgViewHolder(mLayoutInflater.inflate(R.layout
.row_receiver_msg, parent, false));
default:
return null;
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (getItemViewType(position)) {
case ROW_TYPE_LOAD_EARLIER_MESSAGES:
LoadEarlierMsgsViewHolder loadEarlierMsgsViewHolder =
(LoadEarlierMsgsViewHolder) holder;
if (isLoadEarlierMsgs) {
loadEarlierMsgsViewHolder.btLoadEarlierMessages
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mLoadEarlierMessages != null) {
mLoadEarlierMessages.onLoadEarlierMessages();
}
}
});
} else {
loadEarlierMsgsViewHolder.btLoadEarlierMessages.setVisibility(View.GONE);
}
break;
case ROW_TYPE_SENDER:
SenderMsgViewHolder senderMsgViewHolder = (SenderMsgViewHolder) holder;
// set data for your sender chat bubble
break;
case ROW_TYPE_RECEIVER:
ReceiverMsgViewHolder receiverMsgViewHolder = (ReceiverMsgViewHolder) holder;
// set data for your receiver chat bubble
break;
}
}
#Override
public int getItemCount() {
return userMessagesList.size() + 1;
}
#Override
public int getItemViewType(int position) {
if (position == 0) {
return ROW_TYPE_LOAD_EARLIER_MESSAGES; // row load earlier messages
} else if (userMessagesList.get(position - 1).getUser_id() == userId) {
return ROW_TYPE_SENDER; // sender row;
} else {
return ROW_TYPE_RECEIVER; // receiver row;
}
}
public interface LoadEarlierMessages {
void onLoadEarlierMessages();
}
public void setLoadEarlierMsgs(boolean isLoadEarlierMsgs) {
this.isLoadEarlierMsgs = isLoadEarlierMsgs;
}
static class LoadEarlierMsgsViewHolder extends RecyclerView.ViewHolder {
#Bind(R.id.btLoadEarlierMsgs) Button btLoadEarlierMessages;
public LoadEarlierMsgsViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
static class SenderMsgViewHolder extends RecyclerView.ViewHolder {
public SenderMsgViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
static class ReceiverMsgViewHolder extends RecyclerView.ViewHolder {
public ReceiverMsgViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
And finally implement the LoadEarlierMessages listener in your ChatActivity and Override the onLoadEarlierMessages() method
/**
* Created by Mukesh on 21/12/2015.
*/
public class ChatActivity extends AppCompatActivity
implements ChatListAdapter.LoadEarlierMessages {
// getting users recent messages and init RecyclerView
private void showUserMessages() {
// initialising LayoutManager for RecyclerView and setting that to RecyclerView
mLinearLayoutManager = new LinearLayoutManager(this);
mLinearLayoutManager.setStackFromEnd(true); // to start the list from bottom
rvChatsList.setLayoutManager(mLinearLayoutManager);
// initialising RecyclerView Adapter and setting that to the RecyclerView
mChatListAdapter = new ChatListAdapter(this, userId, userMessagesList);
rvChatsList.setAdapter(mChatListAdapter);
// getting count of friend/contact messages and toggling visibility of load more button accordingly
int count = mDataBaseHandler.getCountOfMessages(contactId);
if (count != 0) {
if (count > Constants.MESSAGES_LIMIT_FOR_LOCAL_DATABASE) {
mChatListAdapter.setLoadEarlierMsgs(true);
} else {
mChatListAdapter.setLoadEarlierMsgs(false);
}
userMessagesList.addAll(mDataBaseHandler.getAllMessagesOfContact(contactId));
mChatListAdapter.notifyDataSetChanged();
}
}
#Override
public void onLoadEarlierMessages() {
ArrayList<UserMessage> tempList = mDataBaseHandler
.getPreviousMessagesOfContact(contactId, userMessagesList.size());
if (tempList.size() > 0) {
if (tempList.size() < Constants.MESSAGES_LIMIT_FOR_LOCAL_DATABASE) {
mChatListAdapter.setLoadEarlierMsgs(false);
}
View v = rvChatsList.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
for (int i = 0; i < tempList.size(); i++) {
userMessagesList.add(0, tempList.get(i));
}
mChatListAdapter.notifyDataSetChanged();
mLinearLayoutManager.scrollToPositionWithOffset(tempList.size(), top);
} else {
mChatListAdapter.setLoadEarlierMsgs(false);
}
}
}
Hope this will help..!!
I want to code endless scrolling with Adapters & RecyclerViews and I'm fetching my items with Volley from JSON. Though I have read these guides (Codepath and github), I'm finding it difficult to apply it to my own scenario.
The url of my json has these format: https://example.com/json/items?page=1, https://example.com/json/items?page=2, https://example.com/json/items?page=3 etc.
Below are the codes I'm using:
MainActivity
public class MainActivity extends AppCompatActivity {
private final String TAG = "MainActivity";
private int number = 1;
//Creating a list of videos
private List<VideoItems> mVideoItemsList;
//Creating Views
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private ProgressDialog mProgressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate called");
//Initializing Views
recyclerView = (RecyclerView) findViewById(R.id.video_recycler);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
// This method was copied from codepath (above url)
// Add the scroll listener
recyclerView.addOnScrollListener(new EndlessRecyclerViewScrollListener(layoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount) {
// Triggered only when new data needs to be appended to the list
// Add whatever code needed to append new items of the list
customLoadMoreDataFromApi(page);
}
});
//Initializing the videolist
mVideoItemsList = new ArrayList<>();
adapter = new VideoAdapter(mVideoItemsList, this);
recyclerView.setAdapter(adapter);
if (NetworkCheck.isAvailableAndConnected(this)) {
//Calling method to get data
getData();
} else {
//Codes for building Alert Dialog
alertDialogBuilder.setPositiveButton(R.string.alert_retry, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (!NetworkCheck.isAvailableAndConnected(mContext)) {
alertDialogBuilder.show();
} else {
getData();
}
}
});
alertDialogBuilder.setNegativeButton(R.string.alert_cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
alertDialogBuilder.show();
}
}
public int getNumber() {
return number++;
}
public void setNumber(int number) {
this.number = number;
}
// This method was copied from codepath (above is url)
// Append more data into the adapter
// This method probably sends out a network request and appends new data items to your adapter;
public void customLoadMoreDataFromApi (int offset) {
// Send an API request to retrieve appropriate data using the offset value as a parameter.
// Deserialize API request and then construct new objects to append to the adapter.
// Add the new objects to the data source for adapter
mVideoItemsList.addAll(moreVideos);
// For efficiency purpose, notify the adapter of the only elements inserted that got changed
// curSize will be equal to the index of the first element inserted because the list is 0-indexed
int curSize = adapter.getItemCount();
adapter.notifyItemRangeChanged(curSize, mVideoItemsList.size() - 1);
}
//This method will get data from the web api
private void getData(){
Log.d(TAG, "getData called");
//Codes for Showing progress dialog
//Creating a json request
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigVideo.GET_URL + getNumber(),
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, "onResponse called");
//Dismissing the progress dialog
if (mProgressDialog != null) {
mProgressDialog.hide();
}
//calling method to parse json array
parseData(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
//Creating request queue
RequestQueue requestQueue = Volley.newRequestQueue(this);
//Adding request to the queue
requestQueue.add(jsonArrayRequest);
}
//This method will parse json data
private void parseData(JSONArray array){
Log.d(TAG, "Parsing array");
for(int i = 0; i<array.length(); i++) {
VideoItems videoItem = new VideoItems();
JSONObject jsonObject = null;
try {
jsonObject = array.getJSONObject(i);
videoItem.setVideo_title(jsonObject.getString(ConfigVideo.TAG_VIDEO_TITLE));
videoItem.setVideo_body(jsonObject.getString(ConfigVideo.TAG_VIDEO_BODY));
} catch (JSONException w) {
w.printStackTrace();
}
mVideoItemsList.add(videoItem);
}
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy called");
if (mProgressDialog != null){
mProgressDialog.dismiss();
Log.d(TAG, "mProgress dialog dismissed");
}
}
}
EndlessRecyclerViewScrollListener
The link to the code is EndlessRecyclerViewScrollListener.
In the one in my project, I have deleted all the codes that concerns GridLayoutManager and StaggeredGridLayoutManager since I won't be needing them.
VideoAdapter
public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.ViewHolder>{
private ImageLoader imageLoader;
private Context mContext;
//List of videos
private List<VideoItems> mVideoItems;
public VideoAdapter(List<VideoItems> videoItems, Context context) {
super();
// Getting all videos
this.mVideoItems = videoItems;
this.mContext = context;
}
#Override
public ViewHolder onCreateViewHolder (ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.video_summ, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
VideoItems videoList = mVideoItems.get(position);
holder.videoTitle.setText(videoList.getVideo_title());
holder.videoBody.setText(videoList.getVideo_body());
}
#Override
public int getItemCount(){
//Return the number of items in the data set
return mVideoItems.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
public NetworkImageView videoImage;
public TextView videoTitle, videoBody;
public ViewHolder (View videoView) {
super(videoView);
videoTitle = (TextView) videoView.findViewById(R.id.video_title);
videoBody = (TextView) videoView.findViewById(R.id.video_body);
}
}
}
VideoItems
public class VideoItems {
private String video_title;
private String video_body;
public String getVideo_title() {
return video_title;
}
public void setVideo_title(String video_title) {
this.video_title = video_title;
}
public String getVideo_body() {
return video_body;
}
public void setVideo_body(String video_body) {
this.video_body = video_body;
}
}
I don't know if you could give me tips on how I could implement it to my RecyclerView. Thanks in advance.
You have to implement own listener to the adapter you are binding to recyclerview.
First create a interface like this,
public interface OnLoadMoreListener {
void onLoadMore();
}
In your recyclerview's adapter set this,
adapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
//get your items here based on the pagination count
}
});
Your modified video adapter
public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.ViewHolder>{
private ImageLoader imageLoader;
private Context mContext;
//List of videos
private List<VideoItems> mVideoItems;
private int totalItemCount = 0,lastVisibleItem = 0,int visibleThreshold = 5;
private boolean loading;
private OnLoadMoreListener onLoadMoreListener;
public VideoAdapter(List<VideoItems> videoItems, Context context, RecyclerView recyclerview) {
super();
// Getting all videos
this.mVideoItems = videoItems;
this.mContext = context;
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView
.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView,
int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = layoutManager.getItemCount();
lastVisibleItem = layoutManager.findLastVisibleItemPosition();
if (!loading
&& totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (onLoadMoreListener != null) {
onLoadMoreListener.onLoadMore();
}
loading = true;
}
}
});
}
public void setLoaded() {
loading = false;
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener = onLoadMoreListener;
}
#Override
public ViewHolder onCreateViewHolder (ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.video_summ, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
VideoItems videoList = mVideoItems.get(position);
holder.videoTitle.setText(videoList.getVideo_title());
holder.videoBody.setText(videoList.getVideo_body());
}
#Override
public int getItemCount(){
//Return the number of items in the data set
return mVideoItems.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
public NetworkImageView videoImage;
public TextView videoTitle, videoBody;
public ViewHolder (View videoView) {
super(videoView);
videoTitle = (TextView) videoView.findViewById(R.id.video_title);
videoBody = (TextView) videoView.findViewById(R.id.video_body);
}
}
}
While initializing the adapter send recyclerview object
adapter = new VideoAdapter(mVideoItemsList, this, recyclerView );
Once you get your next set of items, increment your pagecount, notifyDataSetChanged() and call this
adapter.setLoaded();
Hope this will help you!