I'm trying to implement my own VirtualFlow but I'm having some performance issues and I don't understand where the bottleneck could be and what I could do to improve it.
Here's a showcase with two lists, one with simple cells and one with checkboxes too, both have 100_000 items (sorry for the gif quality):
As you can see, I have no issues scrolling through simple cells with just a label, but the list with checkboxes can be quite laggy at the beginning.
To reach such performance (would be much worse otherwise) I memoize my cell factory function so that all cells are ready in memory when needed, I was wondering if there's anything else to make it even faster/smoother.
The code I use to show the cells is:
long start = System.currentTimeMillis();
builtNodes.clear();
for (int i = from; i <= to; i++) {
C cell = cellForIndex.apply(i);
Node node = cell.getNode();
builtNodes.add(node);
}
manager.virtualFlow.container.getChildren().setAll(builtNodes);
long elapsed = System.currentTimeMillis() - start;
System.out.println("Show elapsed: " + elapsed);
I even added this little log, the heavy part seems to be when I call getChildren().setAll(...), both the cell building and the layout are almost immediate
Oh another note on the from and to parameters. When I scroll, I take the scrollbar's value and calculate the first and last visible indexes like this:
public int firstVisible() {
return (int) Math.floor(scrolled / cellHeight);
}
public int lastVisible() {
return (int) Math.ceil((scrolled + virtualFlow.getHeight()) / cellHeight - 1);
}
Edit to answer some questions:
Why implementing my own VirtualFlow?
The ultimate goal would be to make my own ListView implementation, in order to do that I also need a VirtualFlow, also I know it's a pretty low level and hard task, but I think it would be a good way to learn more about programming in general and about JavaFX too
Why memoization?
By caching the cell factory results in memory, it makes subsequent scrolls much faster since nodes are already built they just need to be laid out which is fairly easy. The issue is at the start because for some reason the VirtualFlow lags for more complex cells and I can't understand why since the popular library, Flowless, also uses memoization and caches the nodes in memory, but it is very fluent already from the start. JavaFX's VirtualFlow (revised from JFX16) is also very efficient without memoization, but it's much more complex to comprehend

I finally found a solution that is fast and also efficient for memory.
Instead of building new cells every time the view scrolls and update the children list which is super expensive, I build just the needed amount of cells to fill the viewport. On scroll, the cells are laid out and updated. Updating the cells rather than creating and change the children list is much, much faster.
So, the new implementation is very similar to Android's RecyclerView and maybe also to the JavaFX's VirtualFlow, the only difference being that Cells are dumb, quoting from Flowless:
Everyone can extend the interface and define its own logic.
To show a little bit of code:
The Cell interface:
The CellsManager class, responsible for showing and updating cells:
Maybe it's still not perfect, but it works, I still need to test it properly tough for situations like too many cells, not enough cells, the sizes of the container change so the number of cells must be recomputed again...
Performance now: