Performance e listas grandes
Como manter 60 fps — inclusive em GPU low-end — com muitos dados ou desenho pesado. O “porquê” (paint thread única, render sob demanda) está em A paint thread e O pipeline de renderização.
Virtualize: VirtualListView, não ListView
ListView mantém todos os itens em memória. Para centenas/milhares, use VirtualListView — ele
recicla views (renderiza só o visível). O adapter separa criar (uma vez, reciclado) de
vincular (barato, roda muito):
VirtualListView lista = new VirtualListView(Relative.ofFont(3f), new DataAdapter() {
public int getCount() { return dados.size(); }
public Component createView() throws Exception { // criado poucas vezes (pool)
return new Label("");
}
public void bindView(Component v, int i) throws Exception { // roda MUITO no scroll → barato e idempotente
((Label) v).setText(dados.get(i).nome);
}
});
// ao mudar os dados:
lista.notifyDataChanged();
bindViewdeve ser barato e idempotente — ele roda a cada reciclagem no scroll. Nada de I/O, alocação ou cálculo caro ali.
Por quê reciclar: o custo real é createView(). Reciclando, a memória fica constante
independentemente de getCount() — 10 ou 10.000 itens usam o mesmo punhado de views.
Paginação remota: PagedDataAdapter
Para dados que vêm por página (rede), use PagedDataAdapter (cache LRU interno):
var adapter = new PagedDataAdapter(50, 4) { // 50 itens/página, 4 páginas em cache
public int getTotalCount() { return total; }
public void loadPage(int page, PageCallback cb) {
new Thread(() -> {
Object[] itens = api.buscarPagina(page, pageSize); // fora da paint thread
Component.onUI(() -> cb.onPageLoaded(page, itens)); // volta à 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);
}
};
Desenho: onPaint barato e render sob demanda
- Não repinte por frame. Chame
repaint()só quando o estado muda — a tela não redesenha sozinha (render sob demanda). - Não aloque em
onPaint. Ele roda para a árvore inteira a cada frame; reuse objetos (GRect,Font) em campos, não crie por frame. - Nunca bloqueie a paint thread — I/O de banco/rede em thread de trabalho +
onUI.
Boas práticas
VirtualListViewa partir de ~centenas de itens;ListViewsó para listas pequenas/fixas.bindView/bindItemenxutos; carregue imagens/dados fora e vincule o já-pronto.- Imagens grandes: redimensione uma vez (escala destrutiva) em vez de escalar por frame.
Erros comuns
ListViewcom milhares de itens (estoura memória / trava).bindViewfazendo I/O ou alocando (engasga o scroll).- Repintar em loop/por frame em vez de sob demanda.