9. Persistindo dados
O que você vai aprender: gravar de verdade com SQLite, atrás de um repositório. Pré-requisitos: Carregando dados.
Exemplo completo (copiar, colar e rodar)
Um repositório SQLite (fachada) isolando o SQL, chamado fora da paint thread numa Thread, e o
resultado exibido via Component.onUI. Bind 1-based, cursor 0-based, try-with-resources. Compila como está.
package com.exemplo;
import java.util.*;
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.sqlite.*;
public class MainWindow extends Window
{
private final TarefaRepositorySQLite repo = new TarefaRepositorySQLite();
private final Component listaBox = new Component();
@Override
public void onShow() throws Exception
{
super.onShow();
setLayout(new VerticalLayout());
Button add = new Button("Inserir e recarregar");
add.onAction(c -> new Thread(() -> { // I/O fora da paint thread
repo.inserir("Tarefa " + System.currentTimeMillis());
var dados = repo.listar();
Component.onUI(() -> renderizar(dados)); // volta à paint thread
}).start());
add(LAY_AUTO, add);
listaBox.setLayout(new VerticalLayout());
add(LAY_FILL, listaBox);
new Thread(() -> { // carga inicial em background
var dados = repo.listar();
Component.onUI(() -> renderizar(dados));
}).start();
}
private void renderizar(List<Tarefa> dados)
{
listaBox.removeAll();
for (Tarefa t : dados) listaBox.add(LAY_AUTO, new Label(t.id + " · " + t.titulo));
listaBox.setValidLayout(false);
Component.repaint();
}
}
class Tarefa
{
final int id; final String titulo;
Tarefa(int id, String titulo) { this.id = id; this.titulo = titulo; }
}
class TarefaRepositorySQLite
{
private static final String DB = "tarefas.db";
public TarefaRepositorySQLite()
{
try (SqliteDb db = SqliteDb.open(DB)) {
db.exec("CREATE TABLE IF NOT EXISTS tarefa(id INTEGER PRIMARY KEY, titulo TEXT, feito INTEGER)");
} catch (Exception e) { Debug.handle(e); }
}
public List<Tarefa> listar()
{
List<Tarefa> out = new ArrayList<>();
try (SqliteDb db = SqliteDb.open(DB);
SqliteCursor c = db.query("SELECT id, titulo FROM tarefa ORDER BY id")) {
while (c.next()) // getters 0-based
out.add(new Tarefa(c.getInt(0), c.getString(1)));
} catch (Exception e) { Debug.handle(e); }
return out;
}
public void inserir(String titulo)
{
try (SqliteDb db = SqliteDb.open(DB)) {
db.execute("INSERT INTO tarefa(titulo, feito) VALUES(?, ?)", titulo, 0); // bind 1-based
} catch (Exception e) { Debug.handle(e); }
}
}
Os trechos abaixo mostram só o miolo (o que vai dentro de
onShow()). Para rodar, coloque-os no esqueletoMainWindowacima.
O módulo dev.crossfly.sqlite
SqliteDb/SqliteStmt/SqliteCursor — todos AutoCloseable (use try-with-resources) e rodados
fora da paint thread.
Um repositório (fachada)
Isole o SQL numa classe; a UI nunca fala SQL direto:
public class TarefaRepositorySQLite {
private static final String DB = "tarefas.db";
public TarefaRepositorySQLite() {
try (SqliteDb db = SqliteDb.open(DB)) {
db.exec("CREATE TABLE IF NOT EXISTS tarefa(id INTEGER PRIMARY KEY, titulo TEXT, feito INTEGER)");
} catch (Exception e) { Debug.handle(e); }
}
public List<Tarefa> listar() {
List<Tarefa> out = new ArrayList<>();
try (SqliteDb db = SqliteDb.open(DB);
SqliteCursor c = db.query("SELECT id, titulo FROM tarefa ORDER BY id")) {
while (c.next()) // getters 0-based
out.add(new Tarefa(c.getInt(0), c.getString(1)));
} catch (Exception e) { Debug.handle(e); }
return out;
}
public void inserir(String titulo) {
try (SqliteDb db = SqliteDb.open(DB)) {
db.execute("INSERT INTO tarefa(titulo, feito) VALUES(?, ?)", titulo, 0); // bind 1-based
} catch (Exception e) { Debug.handle(e); }
}
}
⚠️ As duas regras de ouro
| Operação | Base |
|---|---|
bind de parâmetro (?) |
1-based |
| getter de coluna (cursor) | 0-based |
Para escrita em massa, use transaction(...)/bulkInsert(...). Para dados sensíveis, abra com chave
(SqliteDb.open(file, key), ver Segurança).
Constrói neste passo
O TarefaRepositorySQLite — o app agora sobrevive a reinícios.
Recapitulando
SQLite via repositório, try-with-resources, fora da paint thread; bind 1-based, cursor 0-based; transações/bulk para lote.
Próximos passos
Veja também
- Persistência com SQLite · Fonte canônica: Capítulo 23 — SQLite