Introducción
SQLite es una biblioteca de software que proporciona una base de datos relacional ligera y autónoma. Es una opción popular para el almacenamiento local en aplicaciones móviles debido a su simplicidad y eficiencia. En este tema, aprenderás cómo integrar SQLite en tu aplicación Flutter para gestionar datos de manera persistente.
Objetivos de Aprendizaje
- Comprender qué es SQLite y por qué es útil en aplicaciones móviles.
- Configurar SQLite en un proyecto Flutter.
- Crear, leer, actualizar y eliminar (CRUD) datos en una base de datos SQLite.
- Manejar errores comunes y optimizar el rendimiento de las operaciones de base de datos.
Configuración de SQLite en Flutter
Para utilizar SQLite en Flutter, usaremos el paquete sqflite. Sigue estos pasos para configurarlo:
-
Agregar Dependencias: Abre el archivo
pubspec.yamly añade las siguientes dependencias:dependencies: flutter: sdk: flutter sqflite: ^2.0.0+3 path: ^1.8.0 -
Instalar Dependencias: Ejecuta el comando
flutter pub getpara instalar las dependencias. -
Importar Paquetes: Importa los paquetes necesarios en tu archivo Dart:
import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart';
Creación de la Base de Datos
Paso 1: Inicializar la Base de Datos
Crea una función para inicializar la base de datos. Esta función abrirá la base de datos y ejecutará una consulta SQL para crear una tabla si no existe.
Future<Database> initializeDB() async {
String path = await getDatabasesPath();
return openDatabase(
join(path, 'example.db'),
onCreate: (database, version) async {
await database.execute(
"CREATE TABLE items(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, quantity INTEGER NOT NULL)",
);
},
version: 1,
);
}Paso 2: Insertar Datos
Crea una función para insertar datos en la tabla.
Future<void> insertItem(Database db, String name, int quantity) async {
await db.insert(
'items',
{'name': name, 'quantity': quantity},
conflictAlgorithm: ConflictAlgorithm.replace,
);
}Paso 3: Leer Datos
Crea una función para leer datos de la tabla.
Future<List<Map<String, dynamic>>> retrieveItems(Database db) async {
final List<Map<String, dynamic>> queryResult = await db.query('items');
return queryResult;
}Paso 4: Actualizar Datos
Crea una función para actualizar datos en la tabla.
Future<void> updateItem(Database db, int id, String name, int quantity) async {
await db.update(
'items',
{'name': name, 'quantity': quantity},
where: "id = ?",
whereArgs: [id],
);
}Paso 5: Eliminar Datos
Crea una función para eliminar datos de la tabla.
Future<void> deleteItem(Database db, int id) async {
await db.delete(
'items',
where: "id = ?",
whereArgs: [id],
);
}Ejemplo Completo
A continuación, se muestra un ejemplo completo que integra todas las funciones anteriores en una aplicación Flutter.
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
Database? _database;
@override
void initState() {
super.initState();
initializeDB().then((db) {
setState(() {
_database = db;
});
});
}
Future<Database> initializeDB() async {
String path = await getDatabasesPath();
return openDatabase(
join(path, 'example.db'),
onCreate: (database, version) async {
await database.execute(
"CREATE TABLE items(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, quantity INTEGER NOT NULL)",
);
},
version: 1,
);
}
Future<void> insertItem(String name, int quantity) async {
await _database?.insert(
'items',
{'name': name, 'quantity': quantity},
conflictAlgorithm: ConflictAlgorithm.replace,
);
setState(() {});
}
Future<List<Map<String, dynamic>>> retrieveItems() async {
final List<Map<String, dynamic>> queryResult = await _database!.query('items');
return queryResult;
}
Future<void> updateItem(int id, String name, int quantity) async {
await _database?.update(
'items',
{'name': name, 'quantity': quantity},
where: "id = ?",
whereArgs: [id],
);
setState(() {});
}
Future<void> deleteItem(int id) async {
await _database?.delete(
'items',
where: "id = ?",
whereArgs: [id],
);
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SQLite Example'),
),
body: FutureBuilder(
future: retrieveItems(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
final items = snapshot.data as List<Map<String, dynamic>>;
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]['name']),
subtitle: Text('Quantity: ${items[index]['quantity']}'),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
deleteItem(items[index]['id']);
},
),
);
},
);
}
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
insertItem('Item ${DateTime.now()}', 1);
},
child: Icon(Icons.add),
),
);
}
}Ejercicios Prácticos
- Ejercicio 1: Modifica la aplicación para que permita actualizar la cantidad de un ítem existente.
- Ejercicio 2: Añade una funcionalidad para buscar ítems por nombre.
- Ejercicio 3: Implementa una función para ordenar los ítems por cantidad.
Soluciones
Ejercicio 1: Modificar la cantidad de un ítem existente.
// Añadir un botón de edición en cada ListTile
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(Icons.edit),
onPressed: () {
updateItem(items[index]['id'], items[index]['name'], items[index]['quantity'] + 1);
},
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
deleteItem(items[index]['id']);
},
),
],
),Ejercicio 2: Buscar ítems por nombre.
Future<List<Map<String, dynamic>>> searchItems(String name) async {
final List<Map<String, dynamic>> queryResult = await _database!.query(
'items',
where: "name LIKE ?",
whereArgs: ['%$name%'],
);
return queryResult;
}Ejercicio 3: Ordenar los ítems por cantidad.
Future<List<Map<String, dynamic>>> retrieveItemsOrdered() async {
final List<Map<String, dynamic>> queryResult = await _database!.query(
'items',
orderBy: "quantity DESC",
);
return queryResult;
}Conclusión
En esta sección, has aprendido cómo integrar SQLite en una aplicación Flutter para realizar operaciones CRUD. SQLite es una herramienta poderosa para el almacenamiento local y es esencial para aplicaciones que requieren persistencia de datos. Asegúrate de manejar adecuadamente los errores y optimizar las consultas para mantener un rendimiento óptimo.
Curso de Desarrollo con Flutter
Módulo 1: Introducción a Flutter
- ¿Qué es Flutter?
- Configuración del Entorno de Desarrollo
- Entendiendo la Arquitectura de Flutter
- Creando Tu Primera App con Flutter
Módulo 2: Conceptos Básicos de Programación en Dart
- Introducción a Dart
- Variables y Tipos de Datos
- Sentencias de Control de Flujo
- Funciones y Métodos
- Programación Orientada a Objetos en Dart
Módulo 3: Widgets en Flutter
- Introducción a los Widgets
- Widgets Stateless vs Stateful
- Widgets Básicos
- Widgets de Diseño
- Widgets de Entrada y Formularios
Módulo 4: Gestión de Estado
Módulo 5: Navegación y Enrutamiento
- Introducción a la Navegación
- Navegación Básica
- Rutas Nombradas
- Pasando Datos Entre Pantallas
- Deep Linking
Módulo 6: Redes y APIs
- Obteniendo Datos de Internet
- Parseo de Datos JSON
- Manejo de Errores de Red
- Usando APIs REST
- Integración con GraphQL
Módulo 7: Persistencia y Almacenamiento
- Introducción a la Persistencia
- Preferencias Compartidas
- Almacenamiento de Archivos
- Base de Datos SQLite
- Usando Hive para Almacenamiento Local
Módulo 8: Conceptos Avanzados de Flutter
- Animaciones en Flutter
- Custom Paint y Canvas
- Canales de Plataforma
- Isolates y Concurrencia
- Optimización de Rendimiento
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias
- Pruebas de Widgets
- Pruebas de Integración
- Técnicas de Depuración
Módulo 10: Despliegue y Mantenimiento
- Preparación para el Lanzamiento
- Construcción para iOS
- Construcción para Android
- Integración Continua/Despliegue Continuo (CI/CD)
- Mantenimiento y Actualización de Tu App
