This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.
Performance and large lists
How to keep 60 fps — even on low-end GPUs — with lots of data or heavy drawing. The “why” (single paint thread, on-demand render) is in The paint thread and The rendering pipeline.
Virtualize: VirtualListView, not ListView
ListView keeps all items in memory. For hundreds/thousands, use VirtualListView — it
recycles views (renders only what’s visible). The adapter separates create (once, recycled) from
bind (cheap, runs a lot):
VirtualListView lista = new VirtualListView(Relative.ofFont(3f), new DataAdapter() {
public int getCount() { return dados.size(); }
public Component createView() throws Exception { // created only a few times (pool)
return new Label("");
}
public void bindView(Component v, int i) throws Exception { // runs A LOT on scroll → cheap and idempotent
((Label) v).setText(dados.get(i).nome);
}
});
// when the data changes:
lista.notifyDataChanged();
bindViewmust be cheap and idempotent — it runs on every recycle during scrolling. No I/O, allocation, or expensive computation there.
Why recycle: the real cost is createView(). By recycling, memory stays constant regardless of
getCount() — 10 or 10,000 items use the same handful of views.
Remote pagination: PagedDataAdapter
For data that comes in by page (network), use PagedDataAdapter (internal LRU cache):
var adapter = new PagedDataAdapter(50, 4) { // 50 items/page, 4 pages cached
public int getTotalCount() { return total; }
public void loadPage(int page, PageCallback cb) {
new Thread(() -> {
Object[] itens = api.buscarPagina(page, pageSize); // off the paint thread
Component.onUI(() -> cb.onPageLoaded(page, itens)); // back to the UI
}).start();
}
public Component createView() throws Exception { return new Label(""); }
public void bindItem(Component v, Object item, int i) throws Exception {
((Label) v).setText(((Cliente) item).nome);
}
};
Drawing: cheap onPaint and on-demand render
- Don’t repaint every frame. Call
repaint()only when the state changes — the screen doesn’t redraw itself (on-demand render). - Don’t allocate in
onPaint. It runs for the whole tree every frame; reuse objects (GRect,Font) in fields, don’t create them per frame. - Never block the paint thread — database/network I/O on a worker thread +
onUI.
Best practices
VirtualListViewfrom ~hundreds of items on;ListViewonly for small/fixed lists.- Lean
bindView/bindItem; load images/data outside and bind the ready-made result. - Large images: resize once (destructive scaling) instead of scaling per frame.
Common mistakes
ListViewwith thousands of items (blows up memory / freezes).bindViewdoing I/O or allocating (stutters the scroll).- Repainting in a loop/per frame instead of on demand.