Как я использовал SQLite в своем приложении Flutter с sqflite
FlutterPulseЭта статья переведена специально для канала FlutterPulse. В этом канале вы найдёте много интересных вещей, связанных с Flutter. Не забывайте подписываться! 🚀
Раота с локальным хранилищем в Flutter? Если вы хотите сохранять данные, такие как заметки или задачи, без использования интернета, SQLite - отличный вариант…
Раота с локальным хранилищем в Flutter? Если вы хотите сохранять данные, такие как заметки или задачи, без использования интернета, SQLite - отличный вариант.
Это на самом деле моя первая публикация на Medium, и я хотел поделиться чем-то простым, но полезным. В этом руководстве я покажу вам, как использовать пакет sqflite для настройки локальной базы данных и выполнения базовых операций CRUD. Давайте приступим!
Настройка проекта
Перед тем, как приступить к коду, нам нужно добавить необходимые пакеты и настроить структуру.
Добавление зависимостей
Откройте ваш pubspec.yaml и добавьте следующее:
зависимости: flutter: sdk: flutter sqflite: ^2.3.2 path: ^1.8.3
Затем запустите:
flutter pub get в терминале
Предлагаемая структура папок
Вы можете организовать свой проект так, чтобы все было чисто:
lib/
── db/
│ ── database_helper.dart
── models/
│ ── note.dart
── screens/
│ ── home_screen.dart
── main.dart
Создание модели Note
Давайте сделаем все просто с 3 полями: id, title, и content.
Файл: lib/models/note.dart
класс Note {
final int? id;
final String title;
final String content;
Note({this.id, required this.title, required this.content});
// Преобразование объекта Note в Map
Map<String, dynamic> toMap() {
return {
'id': id,
'title': title,
'content': content,
};
}
// Преобразование Map в объект Note
factory Note.fromMap(Map<String, dynamic> map) {
return Note(
id: map['id'],
title: map['title'],
content: map['content'],
);
}
}
Эта модель дает нам два полезных метода:
toMap()→ для сохранения в SQLite.fromMap()→ для чтения из SQLite.
Настройка SQLite с DatabaseHelper
Этот класс будет обрабатывать:
- Создание базы данных
- Определение таблицы
- Вставка, обновление, удаление и получение заметок
Файл: lib/db/database_helper.dart
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import '../models/note.dart';
class DatabaseHelper {
static final DatabaseHelper _instance = DatabaseHelper._internal();
factory DatabaseHelper() => _instance;
DatabaseHelper._internal();
static Database? _database;
Future<Database> get database async {
_database??= await _initDB();
return _database!;
}
Future<Database> _initDB() async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, 'notes.db');
return await openDatabase(
path,
version: 1,
onCreate: _createDB,
);
}
Future _createDB(Database db, int version) async {
await db.execute('''
CREATE TABLE notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT NOT NULL
)
''');
}
// Вставка заметки
Future<int> insertNote(Note note) async {
final db = await database;
return await db.insert('notes', note.toMap(), conflictAlgorithm: ConflictAlgorithm.replace);
}
// Получение всех заметок
Future<List<Note>> getNotes() async {
final db = await database;
final List<Map<String, dynamic>> maps = await db.query('notes');
return maps.map((map) => Note.fromMap(map)).toList();
}
// Обновление заметки
Future<int> updateNote(Note note) async {
final db = await database;
return await db.update(
'notes',
note.toMap(),
where: 'id =?',
whereArgs: [note.id],
);
}
// Удаление заметки
Future<int> deleteNote(int id) async {
final db = await database;
return await db.delete(
'notes',
where: 'id =?',
whereArgs: [id],
);
}
}
Быстрые заметки:
- Мы использовали шаблон одиночка для единственного экземпляра базы данных.
openDatabase()инициализирует и создает таблицуnotesпри первом запуске.- Все методы CRUD являются асинхронными и возвращают стандартные
intилиList<Note>.
Интеграция с UI — отображение и добавление заметок
Мы создадим минимальное приложение с:
- Списком
ListViewдля отображения заметок - FAB для добавления новых заметок
- Простым экраном для добавления или редактирования заметки
Файл: lib/main.dart
import 'package:flutter/material.dart';
import 'screens/home_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SQLite Notes',
theme: ThemeData(primarySwatch: Colors.indigo),
home: const HomeScreen(),
);
}
}
Файл: lib/screens/home_screen.dart
import 'package:flutter/material.dart';
import '../db/database_helper.dart';
import '../models/note.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
List<Note> notes = [];
@override
void initState() {
super.initState();
_loadNotes();
}
Future<void> _loadNotes() async {
final data = await DatabaseHelper().getNotes();
setState(() {
notes = data;
});
}
void _addNoteDialog() {
final titleController = TextEditingController();
final contentController = TextEditingController();
showDialog(
context: context,
builder: (_) => AlertDialog(
title: const Text('Добавить заметку'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(controller: titleController, decoration: const InputDecoration(hintText: 'Заголовок')),
TextField(controller: contentController, decoration: const InputDecoration(hintText: 'Содержание')),
],
),
actions: [
TextButton(
onPressed: () async {
final note = Note(title: titleController.text, content: contentController.text);
await DatabaseHelper().insertNote(note);
Navigator.of(context).pop();
_loadNotes();
},
child: const Text('Сохранить'),
),
],
),
);
}
Future<void> _deleteNote(int id) async {
await DatabaseHelper().deleteNote(id);
_loadNotes();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Мои заметки')),
body: ListView.builder(
itemCount: notes.length,
itemBuilder: (_, index) {
final note = notes[index];
return ListTile(
title: Text(note.title),
subtitle: Text(note.content),
trailing: IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () => _deleteNote(note.id!),
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _addNoteDialog,
child: const Icon(Icons.add),
),
);
}
}
Бонусные советы и подводные камни
Вот несколько практических советов из моего опыта работы с SQLite в Flutter:
- Используйте async/await правильно
Всегда ожидайте вызовы базы данных, чтобы избежать неожиданного поведения или гонок. - База данных сохраняется
Как только база данных создана, она остается до тех пор, пока вы не удалите приложение или не удалите ее вручную. Полезно для тестирования! - Обработка ошибок имеет значение
Оберните операции с базой данных в блокиtry-catch, особенно для функций обновления и удаления. - Используйте TextEditingControllers мудро
Не забудьте их утилизировать, если вы используете несколько экранов ввода.
Заключение
Если вы нашли ее полезной или имеете какие-либо отзывы, не стесняйтесь оставить комментарий или связаться. Я бы с удовольствием услышал ваши мысли!