В этой статье будет использоваться подключаемый модуль sqflite для сохранения структурированных данных в автономном режиме и создания базы данных, хранения, обновления и удаления данных (CRUD) в приложении Flutter.

🟤 Часть 1: Начало

Flutter – это пакет SDK для мобильных приложений, предназначенный для создания высокопроизводительных и качественных приложений для iOS и Android. Flutter работает с существующим кодом, используется разработчиками и организациями по всему миру, является бесплатным и открытым исходным кодом.

В этой статье вы узнаете, как создавать красивые высокопроизводительные приложения за меньшее время и использовать небольшую базу данных SQLite для локального сохранения данных и управления ими.

База данных SQLite — это облегченная встроенная база данных. Его база данных представляет собой файл. SQLite обычно используется мобильными устройствами, веб-сайтами с малым и средним трафиком для систем преобразования версий, инструментов финансового анализа, комплектов каталогизации и редактирования мультимедиа, пакетов САПР, программ ведения учета и т. д. К преимуществам использования SQLite относятся:

✅Можно использовать с любым языком программирования и на любых устройствах

✅Размер базы данных обычно ограничен 2 ГБ

✅ И еще о Школах W3C

Оглавление

  • Включить Sqflite во Flutter
  • Создайте модель во Flutter
  • Создайте таблицу, используя модель во Flutter
  • Вставка/обновление/удаление (CRUD) данных в SQLite
  • Отображение данных из SQLite во Flutter
  • Оптимизация SQLite для производительности во Flutter
  • Загрузите файл SQLite
  • Обновите схему таблицы в SQLite

🟤 Часть 2: Включите Sqflite во Flutter

SQLite – это реляционная база данных с открытым исходным кодом, которую можно использовать для хранения и обработки данных, таких как добавление, удаление и удаление данных.

Для этого не требуется сервер или внутренний код, и все данные сохраняются в текстовом файле на устройстве. Подробнее об этом смотрите здесь.

Шаг1️⃣. Добавьте пакет sqflite в pubspec.yaml.

Посетите pub.dev и добавьте sqflite:^2.0.0+4 в файл pubspec.yaml

environment:
  sdk: ">=2.12.0 <3.0.0"dependencies:
  flutter:
    sdk: flutter
  sqflite: ^2.0.0+4
  path: ^1.8.0

Шаг2️⃣. Добавьте path:^1.8.0plugin во Flutter.

Подключаемый модуль path — это кроссплатформенная библиотека управления путями для Dart, которая помогает указать расположение файла, содержащего базу данных.

Например, если вы хотите присоединиться к пути базы данных:

Шаг3️⃣. Запустите pub get

Ваша поддержка была бы потрясающей❤️

Пожалуйста, помогите мне получить 100 подписчиков.

🟤 Создайте таблицу в SQLite

Шаг1️⃣. Создайте sqlite_service.dart файл в папке службы.

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';class SqliteService {
  Future<Database> initializeDB() async {
    String path = await getDatabasesPath();
    
    return openDatabase(
      join(path, 'database.db'),
      onCreate: (database, version) async {
         await database.execute( 
           "CREATE TABLE Notes(id INTEGER PRIMARY KEY AUTOINCREMENT,  
           description TEXT NOT NULL)",
      );
     },
     version: 1,
    );
  }
}

Шаг2️⃣: инициализируйте базу данных

getDatabasePath(): получает расположение базы данных по умолчанию.

openDatabase(): принимает обязательный String в качестве аргумента, который является путем к базе данных.

✅ Мы используем метод join(), который находится внутри пакета path, чтобы объединить данный путь в один путь, поэтому, например, мы получим databasepath/database.db.

onCreate() обратный вызов: он будет вызываться при первом создании базы данных и выполнит указанный выше SQL-запрос для создания таблицы notes. Именно здесь должно происходить создание таблиц и начальное заполнение таблиц.

🟤 Часть 3: Создание модели во Flutter

Наша цель — сохранить данные в базе данных, например, чтобы сохранить список заметок для приложения со списком задач, поэтому мы создаем класс Note, который будет содержать различные поля, связанные с заметкой.

По сути, эта модель определяет поля, которые можно извлечь из таблицы в базе данных.

class Note{ 
  final int id; 
  final String description;
   
  Note({this.id, this.description});
  
  Note.fromMap(Map<String, dynamic> item): 
    id=item["id"], description= item["description"];
  
  Map<String, Object> toMap(){
    return {'id':id,'description': description};
  }
}

Мы создаем именованный конструктор с именем Note.fromMap() и метод с именем toMap() для преобразования данных в карту и наоборот для управления данными в базе данных SQLite.

🟤 Вставка данных в таблицу в SQLite

Давайте начнем создавать методы CRUD в файле sqlite_service.dart file.

class SqliteService{
  
  Future<int> createItem(Note note) async {
    int result = 0;
    final Database db = await initializeDB();
    final id = await db.insert(
      'Notes', note.toMap(), 
      conflictAlgorithm: ConflictAlgorithm.replace);   }
}

createItem() сделает заметку, а затем вставит заметку в таблицу Notes.

✅ Метод insert(): он принимает 2 аргумента String table, Map<String, Object?> values, поэтому мы создаем метод toMap() в классе модели.

🟤 Получить данные из таблицы в SQLite

class SqliteService{ 
  Future<List<Note>> getItems() async {
    final db = await SqliteService.initizateDb();
    final List<Map<String, Object?>> queryResult = 
      await db.query('Notes', orderBy: NoteColumn.createdAt);
    return queryResult.map((e) => Note.fromMap(e)).toList();
  }
}

✅ Мы используем метод query(), который принимает строковое расширение Notes, которое является именем таблицы, для извлечения всех столбцов из таблицы Notes.

queryResult возвращает List, поэтому мы используем метод map() для преобразования List<Map<String, Object?>> в List<Note>.

🟤 Часть 4: Удаление данных из таблицы в SQLite

class SqliteService{  // Delete an note by id
  Future<void> deleteItem(String id) async {
   final db = await SqliteService.initizateDb();    try {
      await db.delete("Notes", where: "id = ?", whereArgs: [id]);
    } catch (err) {
      debugPrint("Something went wrong when deleting an item: $err");
    }
  }
}

✅ Метод delete(): мы передаем имя таблицы и указываем столбцы, которые мы хотим удалить в таблице.

🟤 Отображение данных из SQLite во Flutter

Мы создаем форму, которая позволяет пользователям заполнять данные, включая описание заметки. При отправке формы данные будут храниться в соответствующих столбцах таблицы.

У нас будет 2 экрана. Начнем с Главного экрана:

Шаг1️⃣. Инициализируйте класс SqliteService class в виджете с отслеживанием состояния.

Внутри _HomePageState мы добавляем следующий код:

class _HomePageState extends State<MyHomePage> {
  late SqliteService _sqliteService;
  @override
  void initState() {
    super.initState();
    this._sqliteService= SqliteService();
    this._sqliteService.initializeDB().whenComplete(() async {
      await _refreshNotes();
      setState(() {});
    });
  }

Мы создаем экземпляр класса SqliteService(), а затем вызываем initalizeDb() для создания базы данных, которая будет содержать таблицу Notes. Когда Future завершено, мы вызываем _refreshNotes(), чтобы получить список свойств в таблице.

Внутри _refreshNotes() у нас будет следующее:

Шаг2️⃣. Получите данные из SQLite на главном экране.

// All items
List<Note> _notes = [];// This function is used to fetch all data from the database
void _refreshNotes() async {  final data = await SqliteService.getItems();
  setState(() {
    _notes = data;
  });
}

✅ Вызываем метод getItems(), который определен в классе SqliteService().

После этого будет вызван setState(() {});, который перестроит дерево виджетов.

🟤 Оптимизация SQLite для производительности во Flutter

Шаг1️⃣. Добавьте базу данных в папку assets.

assets/database.db

Шаг2️⃣. Укажите ресурсы в файле pubspec.yaml.

flutter:
  assets:
    - assets/database.db

Шаг3️⃣. Скопируйте базу данных в свою файловую систему.

Вам решать, хотите ли вы новую копию из активов или всегда копируете актив. Для лучшей производительности лучше скопировать актив только один раз, а затем открыть копию.

import 'package:path/path.dart';
import 'dart:typed_data';
import 'package:flutter/services.dart';var databasesPath = await getDatabasesPath();
var path = join(databasesPath, "database.db");
// Check if the database exists
var exists = await databaseExists(path);
if (!exists) {
  // Should happen only the first time you launch your application
  print("Creating new copy from asset");
  // Make sure the parent directory exists
  try {
    await Directory(dirname(path)).create(recursive: true);
  } catch (_) {}
    
  // Copy from asset
  ByteData data = await rootBundle.load(join("assets", "database.db"));
  List<int> bytes =
  data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
  
  // Write and flush the bytes written
  await File(path).writeAsBytes(bytes, flush: true);
} else {
  print("Opening existing database");
}
// open the database
db = await openDatabase(path, readOnly: true);

🟤 Загрузите файл SQLite

По умолчанию файл базы данных сохраняется в папке data/data/your package name/databases на устройстве Android, а в iOS и macOS — в папке «Документы».

Если вы хотите проверить каталог файлов, следующий оператор покажет путь:

String path = await getDatabasesPath();

В этом руководстве имя пакета — com.lumeidigital.v2. Если я открою Device File Explorer в Android Studio, я смогу получить доступ к файлу базы данных, посетив data/data/com.lumeidigital.v2/databases.

Теперь выберите базу данных и загрузите базу данных с расширением .db,для этого щелкните правой кнопкой мыши имя базы данных и сохраните файл в любом нужном месте, но помните место, затем нажмите ОК в диалоговом окне Сохранить как.

Для просмотра базы данных нам потребовался браузер SQLite, вы можете скачать браузер SQLite с https://sqlitebrowser.org/dl/. Загрузите подходящий браузер SQLite для вашего устройства по приведенной выше ссылке и откройте его.

Если вы используете VS Code, вы можете загрузить расширение под названием SQLite и открыть файл database.db.

ctrl + shift + p, чтобы открыть базу данных

🟤 Обновите схему таблицы в SQLite

В SQLite onCreate()andonUpgrade() вызываются при открытии базы данных. Номер версии — это аргумент типа int, который передается конструктору и сохраняется в файле базы данных SQLite.

onCreate() callback: Вызывается, когда файл базы данных не существовал и был только что создан. Если onCreate() возвращается успешно и не выдает исключение, предполагается, что база данных создана с запрошенным номером версии.

onUpgrade() обратный вызов: вызывается, когда файл базы данных существует, но номер версии ниже запрошенного в конструкторе. В основном он используется, когда необходимо обновить базу данных. Реализация должна использовать этот метод для удаления таблиц, добавления таблиц или других действий, необходимых для обновления до новой версии схемы.

onUpgrade() должен обновить схему таблицы до запрошенной версии.

Future<Database> initializeDB() async {
    String path = await getDatabasesPath();    return openDatabase(
      join(path, 'database.db'),
      onCreate: (database, version) async {
         await database.execute( "CREATE TABLE properties(id INTEGER PRIMARY KEY AUTOINCREMENT, address TEXT NOT NULL)",
      );
     },
     version: 1,
     onUpgrade: (database, oldVersion, newVersion){()=> ....}
    );
  }

Два подхода к изменению схемы таблицы:

1️⃣: Удалите старый файл базы данных, чтобы снова запустить обратный вызов onCreate(). Это идеально во время разработки, когда у вас больше контроля над установленными версиями и потеря данных не является проблемой.

2️⃣: Увеличивайте номер версии, чтобы вызывался обратный вызовonUpgrade(). Во время разработки, когда потеря данных не является проблемой, вы можете выполнить SQL, например DROP TABLE IF EXIST <table name> , чтобы удалить существующие таблицы, и вызвать onCreate() для повторного создания базы данных.

Однако, если приложение выпущено, вам необходимо реализовать миграцию данных в обратном вызовеonUpgrade(), чтобы ваши пользователи не потеряли свои данные.

🟤 Другая интеграция с базой данных

Всегда будет необходимость хранить данные. Вот некоторые базы данных, которые вы можете использовать с Flutter:

Ваша поддержка была бы потрясающей❤️

Пожалуйста, помогите мне получить 100 подписчиков.

Ключевые слова: Flutter, SQLite, база данных, CRUD.

👉 Исходный код обновлен на Github