RecyclerView
has an InfiniteScrollListener and inside that listener, in OnScrolled()
method I calculate visible and total item count to check if new items should be loaded. When totalItemCount and visibleItemCount are the same, it causes an infinite loop of loading. The listener works flawlessly with my other RecyclerView
s which does NOT have CoordinatorLayout
or NestedScrollView
as a parent.
I want to keep this structure because the customer won't accept a change.
I've got a fragment inside an activity that has a layout like this
CoordinatorLayout{
NestedScrollView{
RecyclerView{
}
}
}
compileSdkVersion 24
buildToolsVersion "23.0.3"
...
minSdkVersion 21
targetSdkVersion 24
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
app:layout_behavior="com.paxotic.paxira.util.behavior.AppBarFlingBehavior">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="@dimen/app_bar_height_small"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
app:layout_collapseMode="parallax">
<ImageView
android:id="@+id/img_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.5"
android:scaleType="centerCrop"
tools:src="@drawable/bg_greeting_activity" />
</RelativeLayout>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<include
layout="@layout/activity_profile_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<android.support.design.widget.FloatingActionButton
... />
</android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
...
<android.support.v7.widget.RecyclerView
android:id="@+id/feedRecycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="@dimen/spacing_normal"
tools:listitem="@layout/list_item_activity" />
...
</android.support.v4.widget.NestedScrollView>
private void init() {
feedAdapter = new FeedAdapter(host);
feedAdapter.setHasStableIds(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(host);
feedRecycler.setLayoutManager(layoutManager);
feedRecycler.setNestedScrollingEnabled(false);
feedRecycler.setHasFixedSize(true);
feedRecycler.setAdapter(feedAdapter);
infiniteScrollListener = new InfiniteScrollListener(host, layoutManager) {
@Override
public void onLoadMore(int pageIndex) {
if (!feedAdapter.isLoading) {
loadFeed(pageIndex);
}
}
};
feedRecycler.addOnScrollListener(infiniteScrollListener);
}
public abstract class InfiniteScrollListener extends RecyclerView.OnScrollListener {
private int previousTotal = 0; // The total number of items in the dataset after the last load
private boolean loading = false; // True if we are still waiting for the last set of data to load.
private static final int VISIBLE_THRESHOLD = 5; // The minimum amount of items to have below your current scroll position before loading more.
int firstVisibleItem, visibleItemCount, totalItemCount;
private int current_page = 0;
private int loadingItemCount;
private LinearLayoutManager mLinearLayoutManager;
public InfiniteScrollListener(Context context, LinearLayoutManager linearLayoutManager) {
this.mLinearLayoutManager = linearLayoutManager;
loadingItemCount = context.getResources().getInteger(R.integer.feed_pull_item_count);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy < 0) return; // check for scroll down
visibleItemCount = mLinearLayoutManager.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();
synchronized (this) {
if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + VISIBLE_THRESHOLD)) {
// End has been reached, Do something
current_page++;
onLoadMore(current_page);
loading = true;
}
}
}
public abstract void onLoadMore(int current_page);
public void setLoading(boolean loading) {
this.loading = loading;
}
@Override
public void onScrollStateChanged(RecyclerView view, int scrollState) {
// Don't take any action on changed
}
}
you are getting the same values from getChildCount() getItemCount()
, because the recyclerview will returns the total number of items/child.
you must override one of the method, as per your usage, to get the value you want. Do this in your custom recyclerview adapter.
To do this, add this to your recyclerview adapter:
@Overide
public int getChildCount() {
//return your desired value here after obtaining it
}
You get the real count of views. If adapter has 15 items and ((LinearLayoutManager) myRecyclerView.getLayoutManager()).getChildCount() returns you 7, there is two items visible in view due to max height or static height value after you update new item its till persists same height.
The count of items in the model (adapter) and the count of views are not the same thing.
RecyclerView doesn't hold views for all 15 items in memory, it only has 7 in your case. When you scroll, it reuses those 7 views for displaying different items. The purpose of this is improving the rendering performance.
If you want to get 15, then you should use mAdapter.getItemCount() instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With