Pular para o conteúdo
CrossFly é 100% open sourceSiga no GitHub
CrossFlyCrossFly
Começar

Como acessar o banco fora da paint thread

Propósito. Consultas pesadas (varreduras, bulk, migrações) travam a UI se rodarem na paint thread única do CrossFly. A regra é: faça o I/O do banco numa thread de trabalho e atualize a UI apenas via Component.onUI(...), que reencaminha o código para a thread de UI.

APIs usadas

  • new Thread(Runnable).start() — cria uma thread de trabalho para o acesso ao banco. Todo o SqliteDb/query/bulkInsert roda aqui, longe da paint thread.
  • Component.onUI(Runnable r) — enfileira r para rodar na thread de UI (internamente Gdx.app.postRunnable). Toda manipulação de componentes (setar texto, adicionar itens à lista, repaint) deve acontecer dentro deste callback.
  • SqliteDb / SqliteCursor — abertos e fechados dentro da própria thread (via try-with-resources). Não compartilhe uma conexão entre threads; abra a sua onde vai usar.

Regra de ouro do threading. Ler/escrever no banco: thread de trabalho. Tocar em componentes de UI: Component.onUI. Nunca o contrário — acessar componentes fora da thread de UI causa corrupção; bloquear a paint thread com I/O trava o app.

Coletar antes de sair da thread. O SqliteCursor é AutoCloseable e ligado à sua conexão. Não passe o cursor para dentro do onUI. Materialize os dados (ex.: numa List) na thread de trabalho e passe só a lista pronta para a UI.

Exemplo completo (copiar, colar e rodar)

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

/** Tela principal executável. Aponte o launcher (classname) e rode: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      new Thread(() ->
      {
         // --- thread de trabalho: I/O do banco ---
         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));   // coleta ANTES de sair da thread
         }

         // --- volta para a UI apenas para atualizar componentes ---
         Component.onUI(() ->
         {
            // aqui é seguro tocar em componentes (setar lista, repaint, etc.)
            preencheLista(nomes);
         });
      }).start();
   }

   /** Stub: atualize aqui seus componentes de UI com os dados carregados. */
   private void preencheLista(List<String> nomes)
   {
      // ex.: montar itens numa lista, setar textos, repaint()...
   }
}

O trecho abaixo mostra só o miolo. Para rodar, coloque-o no esqueleto MainWindow acima.

Trecho mínimo

// verificado na fonte: 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 trabalho: I/O do banco ---
   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));   // coleta ANTES de sair da thread
   }

   // --- volta para a UI apenas para atualizar componentes ---
   Component.onUI(() ->
   {
      // aqui é seguro tocar em componentes (setar lista, repaint, etc.)
      preencheLista(nomes);
   });
}).start();

Aprofunde-se

Esta página foi útil?