Esta página fue traducida automáticamente del portugués y puede contener errores. La versión en portugués es la canónica.
9. Persistiendo datos
Lo que vas a aprender: grabar de verdad con SQLite, detrás de un repositorio. Prerrequisitos: Cargando datos.
Ejemplo completo (copiar, pegar y ejecutar)
Un repositorio SQLite (fachada) aislando el SQL, llamado fuera del paint thread en un Thread, y el
resultado mostrado vía Component.onUI. Bind basado en 1, cursor basado en 0, try-with-resources. Compila tal cual.
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 fuera del paint thread
repo.inserir("Tarefa " + System.currentTimeMillis());
var dados = repo.listar();
Component.onUI(() -> renderizar(dados)); // vuelve al paint thread
}).start());
add(LAY_AUTO, add);
listaBox.setLayout(new VerticalLayout());
add(LAY_FILL, listaBox);
new Thread(() -> { // carga inicial en 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); }
}
}
Los fragmentos siguientes muestran solo el núcleo (lo que va dentro de
onShow()). Para ejecutar, colócalos en el esqueletoMainWindowde arriba.
El módulo dev.crossfly.sqlite
SqliteDb/SqliteStmt/SqliteCursor — todos AutoCloseable (usa try-with-resources) y ejecutados
fuera del paint thread.
Un repositorio (fachada)
Aísla el SQL en una clase; la UI nunca habla SQL directamente:
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); }
}
}
⚠️ Las dos reglas de oro
| Operación | Base |
|---|---|
bind de parámetro (?) |
basado en 1 |
| getter de columna (cursor) | basado en 0 |
Para escritura en masa, usa transaction(...)/bulkInsert(...). Para datos sensibles, abre con clave
(SqliteDb.open(file, key), ver Seguridad).
Construyes en este paso
El TarefaRepositorySQLite — la app ahora sobrevive a reinicios.
Recapitulando
SQLite vía repositorio, try-with-resources, fuera del paint thread; bind basado en 1, cursor basado en 0; transacciones/bulk para lotes.
Próximos pasos
Ver también
- Persistencia con SQLite · Fuente canónica: Capítulo 23 — SQLite