# Background work

> The CrossFly threading pattern — Thread/executor off the paint thread, re-entering with onUI.

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

# Background work

This page consolidates the threading pattern that appears in all the previous ones, from the point of view of
**whoever writes the heavy work**. The "why" is in [The paint thread](/docs/concepts/the-paint-thread).

## The canonical template
```java
new Thread(() -> {
   var resultado = trabalhoPesado();        // I/O or CPU — NEVER on the paint thread
   meuComponente.onUI(() -> {               // re-enters the paint thread
      mostrar(resultado);                    // touch the UI only here
      Component.repaint();
   });
}).start();
```
Ways to re-enter the UI:
| Call | Use |
|---|---|
| `Component.onUI(Runnable)` | from any thread, starting from a component |
| `Main.runOnPaintThread(Runnable)` | same, outside the context of a component |
| `Main.runOnPaintThreadAndWait(Runnable)` | same, **blocking** until it finishes |

## React to a UI event on a thread
When a component's handler must run heavy work, use `onActionThread` (runs off the paint
thread) and re-enter with `onUI`:
```java
botao.onActionThread(c -> {
   var dados = baixar();                    // off the paint thread
   c.onUI(() -> lista.setItems(dados));     // back to the UI
});
```

## Timers
For periodic work (polling, watchdog), use the framework timers:
```java
comp.addTimer(1000);   // fires a timer event every 1000 ms (handled in the component)
```

## `util` utilities
- **`ThreadSync`** — a **2-thread** barrier (producer/consumer): `start()`/`start(maxMillis)`,
  `finished(resultado)`, `getResult()`. Useful for waiting on a result from another thread with a timeout.
- **`RunnableWith<T>`** — callback with an argument: `void run(T obj)`. It is the type of the callbacks that
  deliver a value (e.g., `onError` of `GPSThread`).

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

## Best practices
- **All** blocking I/O (DB, HTTP, GPS, BLE) runs **off** the paint thread.
- Touch the UI **only** inside `onUI(...)`/`runOnPaintThread(...)`.
- Stop threads/timers when leaving the screen (in `onRemove()`), otherwise they leak.

## Common mistakes
- Touching widgets from a `Thread` without `onUI(...)` → erratic behavior/freeze.
- `runOnPaintThreadAndWait(...)` called **from inside** the paint thread (deadlock) — use the
  non-blocking variant there.
- Timers/threads not cancelled when switching screens.

## See also
- Concept: [The paint thread](/docs/concepts/the-paint-thread)
- [State management](/docs/data-and-services/state-management) · [Networking and HTTP](/docs/data-and-services/networking-http)
