Создание приложения с поддержкой работы в оффлайне на Flutter & SQLite — лучшие практики сохранения данных
FlutterPulseЭта статья переведена специально для канала FlutterPulse. В этом канале вы найдёте много интересных вещей, связанных с Flutter. Не забывайте подписываться! 🚀

В сегодняшнем мобильном мире функция работы оффлайн является критически важной для плавного пользовательского опыта. Приложение с приоритетом оффлайн обеспечивает, что пользователи могут продолжать использовать приложение даже без подключения к интернету.
В сегодняшнем мобильном мире, функция работы оффлайн является критически важной для плавного пользовательского опыта. Приложение с приоритетом оффлайн обеспечивает, что пользователи могут продолжать использовать приложение даже без подключения к интернету.
Flutter предоставляет несколько решений для сохранения данных, но SQLite остается наиболее мощным вариантом для хранения структурированных данных локально. В этом руководстве мы создадим приложение Flutter с приоритетом оффлайн с SQLite, охватывая:
✅ Почему SQLite?
✅ Настройка SQLite в Flutter
✅ Создание базы данных и таблиц
✅ Выполнение операций CRUD
✅ Синхронизация оффлайн-данных с API
🔹 Почему выбрать SQLite для оффлайн-хранения?
✔ Постоянное хранение — Данные сохраняются даже после закрытия приложения.
✔ Структурированные данные — Использует таблицы и связи, как традиционные базы данных.
✔ Быстрое и легковесное — Идеально для мобильных приложений.
✔ Работает оффлайн — Интернет не требуется для доступа к данным.
✔ Лучшая производительность — Быстрее, чем shared preferences или локальные JSON-файлы.
📌 Шаг 1: Добавление зависимостей
Чтобы использовать SQLite в Flutter, установите пакет sqflite:
dependencies:
flutter:
sdk: flutter
sqflite: ^2.3.0
path_provider: ^2.1.2
Запустите:
flutter pub get
📌 Шаг 2: Настройка базы данных SQLite
🛠 Создание класса помощника базы данных
Мы создадим файл database_helper.dart для инициализации базы данных:
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper {
static final DatabaseHelper _instance = DatabaseHelper._internal();
factory DatabaseHelper() => _instance;
Database? _database;
DatabaseHelper._internal();
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
Future<Database> _initDatabase() async {
String path = join(await getDatabasesPath(), 'app_database.db');
return await openDatabase(
path,
version: 1,
onCreate: _onCreate,
);
}
Future<void> _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
content TEXT,
createdAt TEXT
)
''');
}
}
✔ Использует path_provider для хранения базы данных в локальной директории приложения.
✔ Создает таблицу notes с полями id, title, content, и createdAt.
✔ Обрабатывает инициализацию базы данных только один раз (singleton pattern).
📌 Шаг 3: Выполнение операций CRUD
🔹 Вставка данных
Добавьте новую запись в базу данных:
Future<int> addNote(String title, String content) async {
final db = await DatabaseHelper().database;
return await db.insert('notes', {
'title': title,
'content': content,
'createdAt': DateTime.now().toIso8601String(),
});
}
🔹 Получение данных
Получите все заметки из базы данных:
Future<List<Map<String, dynamic>>> getNotes() async {
final db = await DatabaseHelper().database;
return await db.query('notes', orderBy: 'createdAt DESC');
}
🔹 Обновление данных
Редактирование существующей заметки:
Future<int> updateNote(int id, String title, String content) async {
final db = await DatabaseHelper().database;
return await db.update(
'notes',
{'title': title, 'content': content},
where: 'id = ?',
whereArgs: [id],
);
}
🔹 Удаление данных
Удаление заметки из базы данных:
Future<int> deleteNote(int id) async {
final db = await DatabaseHelper().database;
return await db.delete('notes', where: 'id = ?', whereArgs: [id]);
}
📌 Шаг 4: Отображение данных в интерфейсе
Создание модели заметки
class Note {
final int id;
final String title;
final String content;
final String createdAt;
Note({required this.id, required this.title, required this.content, required this.createdAt});
factory Note.fromMap(Map<String, dynamic> map) {
return Note(
id: map['id'],
title: map['title'],
content: map['content'],
createdAt: map['createdAt'],
);
}
}
Получение и отображение заметок в ListView
import 'package:flutter/material.dart';
class NotesScreen extends StatefulWidget {
@override
_NotesScreenState createState() => _NotesScreenState();
}
class _NotesScreenState extends State<NotesScreen> {
List<Note> _notes = [];
@override
void initState() {
super.initState();
_loadNotes();
}
Future<void> _loadNotes() async {
final notesList = await DatabaseHelper().getNotes();
setState(() {
_notes = notesList.map((note) => Note.fromMap(note)).toList();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Offline Notes')),
body: ListView.builder(
itemCount: _notes.length,
itemBuilder: (context, index) {
final note = _notes[index];
return ListTile(
title: Text(note.title),
subtitle: Text(note.content),
trailing: Text(note.createdAt),
);
},
),
);
}
}
📌 Шаг 5: Синхронизация офлайн-данных с API
Для поддержания синхронизации локальных данных с удалённым сервером реализуйте:
✅ Фоновая синхронизация — Периодическая синхронизация офлайн-данных с API.
✅ Разрешение конфликтов — Обработка изменений, когда приложение онлайн.
✅ Обнаружение состояния сети — Используйте connectivity_plus для проверки подключения.
Обнаружение изменений в сети
Установите:
dependencies:
connectivity_plus: ^5.0.2
import 'package:connectivity_plus/connectivity_plus.dart';
Future<bool> isConnected() async {
var result = await Connectivity().checkConnectivity();
return result != ConnectivityResult.none;
}
Синхронизация данных при наличии подключения
Future<void> syncData() async {
if (await isConnected()) {
final localNotes = await DatabaseHelper().getNotes();
for (var note in localNotes) {
await uploadToServer(note); // Предполагаемый вызов API
}
print('Синхронизация с сервером завершена!');
}
}
📌 Шаг 6: Обработка обновлений базы данных (версионирование)
Если вам нужно изменить структуру базы данных, обновите функцию onUpgrade:
Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
if (oldVersion < 2) {
await db.execute("ALTER TABLE notes ADD COLUMN isSynced INTEGER DEFAULT 0");
}
}
✔ Сохраняет существующие данные пользователя.
✔ Предотвращает потерю данных при обновлении приложения.
🚀 Заключение
SQLite — это мощное решение для создания приложений с приоритетом офлайн-режима в Flutter.
✔ Локальное хранение данных базы для сохранения состояния.
✔ Эффективные операции CRUD для управления данными.
✔ Синхронизация данных офлайн с API при наличии подключения.
✔ Оптимизировано для производительности и версии.
🎯 Что дальше? Оставайтесь на связи за дополнительными лучшими практиками Flutter, оптимизацией производительности и продвинутыми техниками управления состоянием! 🚀🔥