# Trabalho em background

> O padrão de threading do CrossFly — Thread/executor fora da paint thread, reentrando com onUI.

Source: https://crossfly.dev/pt/docs/data-and-services/background-work — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Trabalho em background

Esta página consolida o padrão de threading que aparece em todas as anteriores, do ponto de vista de
**quem escreve o trabalho pesado**. O "porquê" está em [A paint thread](/docs/concepts/the-paint-thread).

## O template canônico
```java
new Thread(() -> {
   var resultado = trabalhoPesado();        // I/O ou CPU — NUNCA na paint thread
   meuComponente.onUI(() -> {               // reentra na paint thread
      mostrar(resultado);                    // tocar a UI só aqui
      Component.repaint();
   });
}).start();
```
Formas de reentrar na UI:
| Chamada | Uso |
|---|---|
| `Component.onUI(Runnable)` | de qualquer thread, a partir de um componente |
| `Main.runOnPaintThread(Runnable)` | idem, fora do contexto de um componente |
| `Main.runOnPaintThreadAndWait(Runnable)` | idem, **bloqueando** até terminar |

## Reagir a um evento de UI numa thread
Quando o handler de um componente deve rodar trabalho pesado, use `onActionThread` (roda fora da paint
thread) e reentre com `onUI`:
```java
botao.onActionThread(c -> {
   var dados = baixar();                    // fora da paint thread
   c.onUI(() -> lista.setItems(dados));     // volta à UI
});
```

## Timers
Para trabalho periódico (polling, watchdog), use os timers do framework:
```java
comp.addTimer(1000);   // dispara um evento de timer a cada 1000 ms (tratado no componente)
```

## Utilitários de `util`
- **`ThreadSync`** — barreira de **2 threads** (produtor/consumidor): `start()`/`start(maxMillis)`,
  `finished(resultado)`, `getResult()`. Útil para esperar um resultado de outra thread com timeout.
- **`RunnableWith<T>`** — callback com argumento: `void run(T obj)`. É o tipo dos callbacks que
  entregam um valor (ex.: `onError` do `GPSThread`).

```java
ThreadSync sync = new ThreadSync();
new Thread(() -> { var r = calcular(); sync.finished(r); }).start();
sync.start(5000);                 // espera até 5 s
Object r = sync.getResult();
```

## Boas práticas
- **Todo** I/O bloqueante (DB, HTTP, GPS, BLE) roda **fora** da paint thread.
- Toque a UI **somente** dentro de `onUI(...)`/`runOnPaintThread(...)`.
- Pare threads/timers ao sair da tela (em `onRemove()`), senão vazam.

## Erros comuns
- Tocar widgets a partir de uma `Thread` sem `onUI(...)` → comportamento errático/travamento.
- `runOnPaintThreadAndWait(...)` chamado **de dentro** da paint thread (deadlock) — use a variante
  não-bloqueante lá.
- Timers/threads não cancelados ao trocar de tela.

## Veja também
- Conceito: [A paint thread](/docs/concepts/the-paint-thread)
- [Gerência de estado](/docs/data-and-services/state-management) · [Rede e HTTP](/docs/data-and-services/networking-http)
