Pular para o conteúdo
CrossFly é 100% open sourceSiga no GitHub
CrossFlyCrossFly
Começar

8. Carregando dados

O que você vai aprender: buscar dados sem travar a UI e exibir listas grandes com eficiência. Pré-requisitos: Gerenciando estado.

Exemplo completo (copiar, colar e rodar)

Carrega os dados numa Thread de fundo, volta à paint thread com Component.onUI e exibe numa lista virtualizada (VirtualListView + DataAdapter) que recicla views. Compila como está.

package com.exemplo;

import java.util.*;
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

public class MainWindow extends Window
{
   private final List<Tarefa> tarefas = new ArrayList<>();
   private VirtualListView lista;

   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      lista = new VirtualListView(Relative.ofFont(3f), new DataAdapter()
      {
         public int getCount() { return tarefas.size(); }
         public Component createView() { return new Label(""); }               // cria uma vez
         public void bindView(Component v, int i) { ((Label) v).setText(tarefas.get(i).titulo); }
      });
      add(LAY_FILL, lista);

      carregar();
   }

   private void carregar()
   {
      new Thread(() -> {
         var dados = listarDoRepositorio();          // trabalho pesado, thread de fundo
         Component.onUI(() -> {                       // volta à paint thread
            tarefas.clear();
            tarefas.addAll(dados);
            lista.notifyDataChanged();                // atualiza a lista virtualizada
         });
      }).start();
   }

   private List<Tarefa> listarDoRepositorio()        // simula I/O
   {
      List<Tarefa> out = new ArrayList<>();
      for (int i = 1; i <= 500; i++) out.add(new Tarefa("Tarefa " + i));
      return out;
   }
}

class Tarefa
{
   final String titulo;
   Tarefa(String titulo) { this.titulo = titulo; }
}

Os trechos abaixo mostram só o miolo (o que vai dentro de onShow()). Para rodar, coloque-os no esqueleto MainWindow acima.

Por que I/O nunca ocorre na paint thread

A UI roda numa thread só — qualquer bloqueio nela congela a tela. O padrão obrigatório:

new Thread(() -> {
   var dados = repo.listar();                          // trabalho pesado, thread de fundo
   Component.onUI(() -> {                               // volta à paint thread
      vm.tarefas = dados;
      lista.notifyDataChanged();                        // atualiza a lista virtualizada
   });
}).start();

Para reagir a um evento de UI já em background, use onActionThread (ver Lidando com entrada).

Listas grandes: VirtualListView + DataAdapter

VirtualListView recicla views — renderiza só o visível. O adapter separa criar (uma vez) de vincular (barato, muitas vezes):

VirtualListView lista = new VirtualListView(Relative.ofFont(3f), new DataAdapter() {
   public int getCount() { return vm.tarefas.size(); }
   public Component createView() throws Exception { return new CardTarefa(); }
   public void bindView(Component v, int i) throws Exception { ((CardTarefa) v).bind(vm.tarefas.get(i)); }
});
add(LAY_FILL, lista);
// quando os dados mudam:
lista.notifyDataChanged();

bindView roda muito no scroll — mantenha-o barato e idempotente (nada de I/O ali).

Constrói neste passo

A lista passa a carregar em background e a renderizar virtualizada (usando o CardTarefa do capítulo 3).

Recapitulando

I/O em Thread → Component.onUI; listas grandes com VirtualListView (reciclagem via createView/bindView); notifyDataChanged() ao mudar os dados.

Próximos passos

→ Persistindo dados

Veja também

Esta página foi útil?