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 oSqliteDb/query/bulkInsertroda aqui, longe da paint thread.Component.onUI(Runnable r)— enfileirarpara rodar na thread de UI (internamenteGdx.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 (viatry-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éAutoCloseablee ligado à sua conexão. Não passe o cursor para dentro doonUI. Materialize os dados (ex.: numaList) 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
MainWindowacima.
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();