# Cómo acceder a la base de datos fuera de la paint thread

> Ejecutar consultas SQLite en un hilo de trabajo y volver a la UI con Component.onUI.

Source: https://crossfly.dev/es/docs/cookbook/data/banco-fora-da-paint-thread — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Cómo acceder a la base de datos fuera de la paint thread

**Propósito.** Las consultas pesadas (escaneos, bulk, migraciones) bloquean la UI si se ejecutan en la paint thread única de CrossFly. La regla es: **haz el I/O de la base de datos en un hilo de trabajo** y **actualiza la UI solo vía `Component.onUI(...)`**, que reenvía el código al hilo de UI.

## APIs usadas
- `new Thread(Runnable).start()` — crea un hilo de trabajo para el acceso a la base de datos. Todo el `SqliteDb`/`query`/`bulkInsert` se ejecuta aquí, lejos de la paint thread.
- `Component.onUI(Runnable r)` — encola `r` para ejecutarse en el **hilo de UI** (internamente `Gdx.app.postRunnable`). **Toda** manipulación de componentes (asignar texto, agregar ítems a la lista, `repaint`) debe ocurrir dentro de este callback.
- `SqliteDb` / `SqliteCursor` — abiertos y **cerrados dentro del propio hilo** (vía `try-with-resources`). No compartas una conexión entre hilos; abre la tuya donde vayas a usarla.

> **Regla de oro del threading.** Leer/escribir en la base de datos: hilo de trabajo. Tocar componentes de UI: `Component.onUI`. Nunca al revés — acceder a componentes fuera del hilo de UI causa corrupción; bloquear la paint thread con I/O congela la app.

> **Recolecta antes de salir del hilo.** El `SqliteCursor` es `AutoCloseable` y está ligado a su conexión. **No** pases el cursor dentro del `onUI`. Materializa los datos (ej.: en una `List`) en el hilo de trabajo y pasa solo la lista lista para la UI.

## Ejemplo completo (copiar, pegar y ejecutar)

```java
package com.exemplo;

import java.util.*;                          // List, ArrayList

import dev.crossfly.ui.*;                     // Window, Component
import dev.crossfly.ui.layout.*;             // VerticalLayout
import dev.crossfly.sqlite.*;                // SqliteDb, SqliteCursor

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      new Thread(() ->
      {
         // --- thread de trabajo: I/O de la base de datos ---
         List<String> nomes = new ArrayList<>();
         try (SqliteDb db = SqliteDb.open("app.db");
              SqliteCursor c = db.query("SELECT name FROM person ORDER BY name"))
         {
            while (c.next())
               nomes.add(c.getString(0));   // recolecta ANTES de salir de la thread
         }

         // --- vuelve a la UI solo para actualizar componentes ---
         Component.onUI(() ->
         {
            // aquí es seguro tocar componentes (setear lista, repaint, etc.)
            preencheLista(nomes);
         });
      }).start();
   }

   /** Stub: actualiza aquí tus componentes de UI con los datos cargados. */
   private void preencheLista(List<String> nomes)
   {
      // ej.: armar ítems en una lista, setear textos, repaint()...
   }
}
```

> El fragmento de abajo muestra **solo el núcleo**. Para ejecutarlo, colócalo en el esqueleto `MainWindow` de arriba.

## Fragmento mínimo
```java
// verificado en la fuente: Component.onUI (Gdx.app.postRunnable), SqliteDb.query/cursor 0-based
import dev.crossfly.sqlite.*;
import dev.crossfly.ui.Component;
import java.util.*;

new Thread(() ->
{
   // --- thread de trabajo: I/O de la base de datos ---
   List<String> nomes = new ArrayList<>();
   try (SqliteDb db = SqliteDb.open("app.db");
        SqliteCursor c = db.query("SELECT name FROM person ORDER BY name"))
   {
      while (c.next())
         nomes.add(c.getString(0));   // recolecta ANTES de salir de la thread
   }

   // --- vuelve a la UI solo para actualizar componentes ---
   Component.onUI(() ->
   {
      // aquí es seguro tocar componentes (setear lista, repaint, etc.)
      preencheLista(nomes);
   });
}).start();
```

## Profundiza
- [Trabajo en background](/docs/data-and-services/background-work) · [Manejo de errores y logging](/docs/best-practices/seguranca)
- Recetas hermanas: [CRUD parametrizado](/docs/cookbook/data/crud) · [Transacción y escritura masiva](/docs/cookbook/data/transacao-e-bulk)
