# How to access the database outside the paint thread

> Run SQLite queries on a worker thread and return to the UI with Component.onUI.

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

# How to access the database outside the paint thread

**Purpose.** Heavy queries (scans, bulk, migrations) freeze the UI if they run on CrossFly's single paint thread. The rule is: **do the database I/O on a worker thread** and **update the UI only via `Component.onUI(...)`**, which reroutes the code to the UI thread.

## APIs used
- `new Thread(Runnable).start()` — creates a worker thread for database access. All `SqliteDb`/`query`/`bulkInsert` runs here, away from the paint thread.
- `Component.onUI(Runnable r)` — queues `r` to run on the **UI thread** (internally `Gdx.app.postRunnable`). **All** component manipulation (setting text, adding items to the list, `repaint`) must happen inside this callback.
- `SqliteDb` / `SqliteCursor` — opened and **closed within the thread itself** (via `try-with-resources`). Do not share a connection between threads; open your own where you're going to use it.

> **Golden threading rule.** Read/write the database: worker thread. Touch UI components: `Component.onUI`. Never the other way around — accessing components off the UI thread causes corruption; blocking the paint thread with I/O freezes the app.

> **Collect before leaving the thread.** The `SqliteCursor` is `AutoCloseable` and tied to its connection. **Do not** pass the cursor into `onUI`. Materialize the data (e.g., into a `List`) on the worker thread and pass only the finished list to the UI.

## Full example (copy, paste and run)

```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

/** Runnable main screen. Point the launcher (classname) and run: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      new Thread(() ->
      {
         // --- worker thread: database I/O ---
         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));   // collects BEFORE leaving the thread
         }

         // --- back to the UI only to update components ---
         Component.onUI(() ->
         {
            // here it's safe to touch components (set list, repaint, etc.)
            preencheLista(nomes);
         });
      }).start();
   }

   /** Stub: update your UI components here with the loaded data. */
   private void preencheLista(List<String> nomes)
   {
      // e.g. build items in a list, set texts, repaint()...
   }
}
```

> The snippet below shows **only the core**. To run it, place it inside the `MainWindow` skeleton above.

## Minimal snippet
```java
// verified in the source: Component.onUI (Gdx.app.postRunnable), SqliteDb.query/cursor 0-based
import dev.crossfly.sqlite.*;
import dev.crossfly.ui.Component;
import java.util.*;

new Thread(() ->
{
   // --- worker thread: database I/O ---
   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));   // collects BEFORE leaving the thread
   }

   // --- back to the UI only to update components ---
   Component.onUI(() ->
   {
      // here it's safe to touch components (set list, repaint, etc.)
      preencheLista(nomes);
   });
}).start();
```

## Dig deeper
- [Background work](/docs/data-and-services/background-work) · [Error handling and logging](/docs/best-practices/seguranca)
- Sibling recipes: [Parameterized CRUD](/docs/cookbook/data/crud) · [Transaction and bulk writing](/docs/cookbook/data/transacao-e-bulk)
