Lazy Loading for a Nested Recycler-View using pool-interval

Amit Kumar
Bobble Engineering
Published in
3 min readSep 7, 2020

Recycler-view plays a very important role in our day to day apps by loading dynamic data-list as per user’s scroll. Normally we prefer recycler-view because it loads list-item in chunks as per the display size which makes it very fast, smooth and less expensive.

But when we talk about a nested recycler-view it leaves certain limitations on which we are going to talk in this blog.

A Nested Recycler-View

In case of nested, the outer recycler-view behaves quite normal and loads the list as per user’s scroll, on the other hand the inner recycler-view loads the entire list on respective position without taking care of the scroll. Still it behave normal if we have smaller list, but it starts creating multiple performance related issues like:

  1. Memory overhead that results Out of Memory Exception
  2. ANRs and Frozen Frames while loading big list in the child adapter
  3. Laggy Scrolling
  4. Slow UI and Data Rendering
  5. CPU Consumption

Let’s talk about a very effective easy solution to handle this scenario:

We can create a pool-interval and load limited data as per our choice on user’s scroll. We just need to capture user’s scroll of outer recycler-view inside addOnScrollListener and here we can restrict loading full list by placing the below logic:

while(count >= 0) {
mThemesPool = new ArrayList<>();
if (count > 0) { // count is the quotient value of listSize and poolSize
mThemesPool.addAll(themesList.subList(poolInterval, poolInterval + poolSize));
....
....
// poolSize is the fixed listSize to be loaded on scroll
poolInterval = poolInterval + poolSize;
// poolInterval is the temporary poolSize
} else {
if (themesList.size() % poolSize != 0) {
mThemesPool.addAll(themesList.subList(poolInterval, poolInterval + themesList.size() % poolSize));
....
....
} else {
mThemesPool.addAll(themesList.subList(poolInterval, poolInterval + poolSize));
....
....
}
// Reset interval and count for a particular position
poolInterval = 0;
count = -1;
}
// Decrementing count on for loading next interval
count--;
}

We can capture user’s scroll and place the logic below, dx will be returning the horizontal scroll data where as dy will be giving vertical scroll value which can be used for capturing respective scrolls:

/***
* Adding OnScroll listener for parent RecyclerView
*/
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// checking on if the view got scrolled and themeList is greater than pool-size
...
...
}
}
});

This is how we can set the poolSize and load the view on user’s scroll, the above logic can be run in a loop until the mod of listSize and poolSize has been loaded. For example, if the listSize is 87 and poolSize is set to 20 thus the loop will run 4 times with full set of loading 20 item and the 5th loop will load remaining 7 items.

Few important initialisations:

private List<ApiTheme> mThemesPool = new ArrayList<>();
private int poolSize = 30;
private int poolInterval = 10;
private int count = -1;

At the other side, the child adapter will be receiving the listItem with respective poolSize and load on scroll without affecting the app performance. Make sure the object references have been taken care correctly while feeding the list data for child’s bindViewHolder, we might get duplicate entries.

This is how we can create a customised viewPool for our nested recycler-view to address this problem statement and handle multiple issues listed above.

Cheers.

--

--