This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.
9. Persisting data
What you will learn: actually writing to disk with SQLite, behind a repository. Prerequisites: Loading data.
Complete example (copy, paste and run)
A SQLite repository (facade) isolating the SQL, called off the paint thread in a Thread, and the
result displayed via Component.onUI. 1-based bind, 0-based cursor, try-with-resources. Compiles as is.
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 off the paint thread
repo.inserir("Tarefa " + System.currentTimeMillis());
var dados = repo.listar();
Component.onUI(() -> renderizar(dados)); // back to the paint thread
}).start());
add(LAY_AUTO, add);
listaBox.setLayout(new VerticalLayout());
add(LAY_FILL, listaBox);
new Thread(() -> { // initial load in 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); }
}
}
The snippets below show only the core (what goes inside
onShow()). To run them, place them in theMainWindowskeleton above.
The dev.crossfly.sqlite module
SqliteDb/SqliteStmt/SqliteCursor — all AutoCloseable (use try-with-resources) and run
off the paint thread.
A repository (facade)
Isolate the SQL in a class; the UI never speaks SQL directly:
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); }
}
}
⚠️ The two golden rules
| Operation | Base |
|---|---|
parameter bind (?) |
1-based |
| column getter (cursor) | 0-based |
For bulk writes, use transaction(...)/bulkInsert(...). For sensitive data, open with a key
(SqliteDb.open(file, key), see Security).
What you build in this step
The TarefaRepositorySQLite — the app now survives restarts.
Recap
SQLite via a repository, try-with-resources, off the paint thread; 1-based bind, 0-based cursor; transactions/bulk for batches.
Next steps
See also
- Persistence with SQLite · Canonical source: Chapter 23 — SQLite