Skip to content
CrossFly is 100% open sourceFollow us on GitHub
CrossFlyCrossFly
Get started

This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.

8. Loading data

What you’ll learn: fetching data without freezing the UI and displaying large lists efficiently. Prerequisites: Managing state.

Complete example (copy, paste, and run)

Loads the data on a background Thread, comes back to the paint thread with Component.onUI, and displays it in a virtualized list (VirtualListView + DataAdapter) that recycles views. Compiles as is.

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(""); }               // creates once
         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();          // heavy work, background thread
         Component.onUI(() -> {                       // back to the paint thread
            tarefas.clear();
            tarefas.addAll(dados);
            lista.notifyDataChanged();                // updates the virtualized list
         });
      }).start();
   }

   private List<Tarefa> listarDoRepositorio()        // simulates 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; }
}

The snippets below show only the core (what goes inside onShow()). To run them, put them in the MainWindow skeleton above.

Why I/O never happens on the paint thread

The UI runs on a single thread — any blocking on it freezes the screen. The mandatory pattern:

new Thread(() -> {
   var dados = repo.listar();                          // heavy work, background thread
   Component.onUI(() -> {                               // back to the paint thread
      vm.tarefas = dados;
      lista.notifyDataChanged();                        // updates the virtualized list
   });
}).start();

To react to a UI event already in the background, use onActionThread (see Handling input).

Large lists: VirtualListView + DataAdapter

VirtualListView recycles views — it renders only what’s visible. The adapter separates creating (once) from binding (cheap, many times):

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);
// when the data changes:
lista.notifyDataChanged();

bindView runs a lot during scroll — keep it cheap and idempotent (no I/O in there).

What you build in this step

The list now loads in the background and renders virtualized (using the CardTarefa from chapter 3).

Recap

I/O in a Thread → Component.onUI; large lists with VirtualListView (recycling via createView/bindView); notifyDataChanged() when the data changes.

Next steps

→ Persisting data

See also

Was this page helpful?