This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.
How to paginate server data in a virtual list
Purpose. Display a large dataset whose source is paginated (e.g., a REST API) without
loading everything at once. The PagedDataAdapter keeps an LRU cache of pages: only a limited
number of pages stays in memory; when scrolling to a region whose data was discarded, a
spinner appears and the page is reloaded via loadPage. Scrolling is locked while the page
loads.
APIs used
abstract class PagedDataAdapter(int pageSize, int maxCachedPages)—pageSizeitems per page; at mostmaxCachedPagespages in memory (LRU). ImplementsVirtualListView.DataAdapter.abstract int getTotalCount()— total number of items on the server (becomes the list’sgetCount()).abstract void loadPage(int pageIndex, PageCallback callback)— loads a page asynchronously; when done, callcallback.onPageLoaded(pageIndex, items). Can be called from any thread — the list switches to the UI.abstract Component createView() throws Exception— creates the reusable blank view.abstract void bindItem(Component view, Object item, int index) throws Exception— populates the view with the item object (not the text). Unlike the rawbindView: here you receive the item already resolved by the page.interface PageCallback { void onPageLoaded(int pageIndex, Object[] items); }PagedDataAdapter.isAvailable(int index)— true if the index is already in the cache.PagedDataAdapter.clearCache()— clears the cache and loading state.
Complete example (copy, paste and run)
package com.exemplo;
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.graphics.*; // Relative (for VirtualListView)
/** Runnable main screen. Point the launcher (classname) and run: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
/** Simulated business item — replace with your real entity. */
static class Registro
{
final String nome;
Registro(String nome) { this.nome = nome; }
String getNome() { return nome; }
}
static final int totalNoServidor = 12345; // e.g.: API metadata
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
PagedDataAdapter adapter = new PagedDataAdapter(20, 5) // 20 items/page, 5 pages in memory
{
public int getTotalCount()
{
return totalNoServidor;
}
public void loadPage(int pageIndex, PageCallback callback)
{
// async: here we simulate the server response in the background
onUI(() ->
{
Object[] registros = new Object[20];
for (int i = 0; i < registros.length; i++)
registros[i] = new Registro("Item " + (pageIndex * 20 + i));
callback.onPageLoaded(pageIndex, registros);
});
}
public Component createView() throws Exception
{
return new Label(""); // reusable simple row
}
public void bindItem(Component view, Object item, int index) throws Exception
{
Registro r = (Registro) item; // the already-resolved item from the page
((Label) view).setText(r.getNome());
}
};
// PagedDataAdapter is a DataAdapter: pass it straight to VirtualListView
VirtualListView lista = new VirtualListView(Relative.ofFont(3f), adapter);
add(LAY_FILL, lista);
}
}
The snippet below shows only the core. To run it, place it inside the
MainWindowskeleton above.
Minimal snippet
// verified in source: PagedDataAdapter.java
PagedDataAdapter adapter = new PagedDataAdapter(20, 5) // 20 items/page, 5 pages in memory
{
public int getTotalCount()
{
return totalNoServidor; // e.g.: 12345 (coming from API metadata)
}
public void loadPage(int pageIndex, PageCallback callback)
{
// async: fires the request and responds via the callback
api.buscarPagina(pageIndex, 20, registros ->
callback.onPageLoaded(pageIndex, registros)); // records = Object[]
}
public Component createView() throws Exception
{
return new Label(""); // reusable simple row
}
public void bindItem(Component view, Object item, int index) throws Exception
{
Registro r = (Registro) item; // the already-resolved item from the page
((Label) view).setText(r.getNome());
}
};
// PagedDataAdapter is a DataAdapter: pass it straight to VirtualListView
VirtualListView lista = new VirtualListView(Relative.ofFont(3f), adapter);
layout.add(1f, lista);
Go deeper
- The
VirtualListViewbinds to the adapter automatically in the constructor (adapter.listView = this) — no need to wire it manually. - While
loadPageis in flight, the adapter markswaitingForDataand theVirtualListViewblocks pan/fling/wheel and pauses the current fling (resumed when the page arrives). - For infinite scroll by append (without an LRU cache), see carregar-mais.md.
- Widget guide: PagedDataAdapter · Best practices: Performance and large lists · Canonical source: Chapter 15
Was this page helpful?Thanks for the feedback!