SQLite con sqflite en Flutter: ejercicio resuelto CRUD

SQLite con sqflite en Flutter: ejercicio resuelto

Si necesitas SQLite en Flutter con sqflite, este ejercicio muestra un CRUD mínimo para tareas locales.

Enunciado

Crea una tabla tasks, inserta tareas y lístalas en pantalla.

Solución en Flutter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import 'package:flutter/material.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

Future<Database> openDb() async {
  return openDatabase(
    join(await getDatabasesPath(), 'tasks.db'),
    version: 1,
    onCreate: (db, _) {
      return db.execute('CREATE TABLE tasks(id INTEGER PRIMARY KEY, title TEXT)');
    },
  );
}

void main() => runApp(const MaterialApp(home: TasksPage()));

class TasksPage extends StatefulWidget {
  const TasksPage({super.key});

  @override
  State<TasksPage> createState() => _TasksPageState();
}

class _TasksPageState extends State<TasksPage> {
  final ctrl = TextEditingController();
  List<Map<String, dynamic>> tasks = [];

  Future<void> refreshTasks() async {
    final db = await openDb();
    tasks = await db.query('tasks', orderBy: 'id DESC');
    setState(() {});
  }

  Future<void> addTask() async {
    final db = await openDb();
    await db.insert('tasks', {'title': ctrl.text.trim()});
    ctrl.clear();
    await refreshTasks();
  }

  @override
  void initState() {
    super.initState();
    refreshTasks();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('sqflite CRUD')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(12),
            child: Row(
              children: [
                Expanded(child: TextField(controller: ctrl, decoration: const InputDecoration(labelText: 'Tarea'))),
                IconButton(onPressed: addTask, icon: const Icon(Icons.add)),
              ],
            ),
          ),
          Expanded(
            child: ListView.builder(
              itemCount: tasks.length,
              itemBuilder: (_, i) => ListTile(title: Text(tasks[i]['title'] as String)),
            ),
          ),
        ],
      ),
    );
  }
}

Resultado esperado

Las tareas se guardan localmente y persisten entre sesiones.

Errores frecuentes

  • Crear la base de datos varias veces sin control.
  • No usar await en operaciones de escritura.
  • Mezclar modelo de datos y UI en la misma capa.

Aplicación práctica

Es base para apps offline-first, notas, inventarios y trackers personales.

Siguiente ejercicio recomendado

Práctica guiada y siguiente paso

FAQ

¿sqflite es suficiente para una app real?

Sí, para muchos casos offline locales funciona correctamente.

¿Conviene usar ORM en Flutter?

Depende de complejidad. Para apps simples, consultas directas pueden ser suficientes.

¿SQLite o backend remoto?

No son excluyentes. Muchas apps usan SQLite como cache local y API remota como fuente principal.