Ранее мы писали статью про реализацию паттерна MVVM на Флаттере. В комментариях к ней просили разобрать связку нашего приложения с базой данных.  Стоит заметить, что локальная БД в данном случае будет использоваться для кеширования данных, получаемых с бэкенда, однако взаимодействие с бэком не будет рассматриваться здесь, так как это тема, достойная отдельной статьи. Меня зовут Ричард, и я младший разработчик в компании Digital Design. Здесь будет разобрана конкретная реализация, однако я постараюсь использовать максимально общий язык для описания происходящего. Предположим, что у нас есть бэк с основной базой данных и несколько мобильных клиентов нашего ToDoList’а (опять же отсылаю к прошлой статье). На мобилке у нас реализована логика взаимодействия с нашим бэком, однако возникает проблема: где хранить полученные данные?  Мы можем создать массив где-то в нашей программе, но при закрытии приложения мы будем терять все данные. К тому же в таком случае нам придётся держать в памяти сразу все полученные данные, что может быть проблематично. Что же делать в таком случае? Использовать локальную базу данных! Использовать мы будем SQLite, так как она достаточно быстрая и легковесная для работы на мобильном устройстве. Для реализации задумки нам нужно добавить следующие пакеты в проект: sqflite — для подключения SQLite базы данных в Flutter path — для облегчения работы с путями (необязательно) Для этого можно отредактировать файл pubspec.yaml, добавив в него зависимость от этих пакетов либо выполнив команду в консоли: flutter pub add sqflite path — данная команда, собственно, и добавит зависимости в тот же файл и скачает пакеты последней версии. Создадим файл, в котором мы опишем структуру нашей будущей БД, и добавим его как asset в pubspec.yaml   Внутри файла создадим таблицу с нашими ToDo’шками. Забегая чуть вперёд, скажу, что при добавлении нескольких таблиц лучше всего использовать одинаковое название для первичных ключей и один паттерн именования таблиц. Определим абстрактный класс для работы с БД. В нём мы объявим:  Id, не привязанный к конкретному типу; методы по перегонке нашего объекта в Map (и обратно), так как вся работа с базой происходит через неё. Теперь реализуем интерфейс DbModel в нашей модельке ToDoItem.    База данных у нас будет синглтоном, который запускается вместе с приложением. Sqflite предоставляет нам класс Database, в котором содержится интерфейс обращения к БД. Создадим класс DB, в котором будет описана наша логика работы с базой: её инициализация, создание и CRUD-операции. Начнём с инициализации. Для этого мы должны указать путь до файла с БД и открыть его. При открытии БД sqflite проверяет существование указанного файла. Если его нет, то отрабатывается метод _createDB, который мы ему передаём.   В нашем случае мы просто считываем строку из файла, разбиваем по символу ‘;’ и говорим базе выполнить каждую из полученных строк.   Так как из базы мы получаем данные в виде Map, то имеет смысл хранить все фабрики в одном месте и по передаваемому типу получать нужную фабрику. Также при работе с БД нам постоянно потребуется указывать название рабочей таблицы, поэтому напишем метод, который для указанного класса вернёт нужное название:   Create: Read по Id:  Для получения всех строк из таблицы достаточно убрать условие where. В таком случае есть смысл использовать параметры offset и take для ограничения количества возвращаемых записей.   Read с ограничением по количеству записей:   Update:   Delete:   Довольно удобно бывает объединить операции create и update в одном методе.   Create + Update:   Проделанная до этого нами работа — это необходимый минимум. Однако в процессе разработки обнаруживается, что мы часто используем одни и те же запросы. Так создадим специальный сервис для хранения таких запросов. Получение списка задач: Все запросы, которые были написаны для нашего ToDoList’а, мы разбирать не будем, так как они достаточно тривиальны (просто вызывают соответствующие методы из нашего класса DB). При желании можете посмотреть их здесь.   Вернёмся к тому, что было сделано в прошлой статье. У нас были следующие классы:   _ModelState:   _ViewModel:   Добавим сюда наш DataService и создадим метод, который при создании экземпляра _ViewModel будет загружать задачи из базы.   Что же находится внутри SyncService? Просто получение данных с API и добавление их в базу:   Подробнее про `rangeUpdateEntities` Когда мы всё добавили — настала пора проверять работу нашего приложения. Вуаля. Теперь все наши задачи не теряются при закрытии приложения. Исходники проекта Вариант приложения без работы с бэкендом Итак, мы рассмотрели вариант использования локальной базы данных в нашем мобильном приложении. Может быть, вы знаете более удобный способ организации работы с мобильной БД. Поделитесь личным опытом в комментариях! Что делать дальше? Научить своё приложение обмениваться данными с бэкендом! В следующей статье я подробно расскажу о том, как организовать взаимодействие между мобильным приложением и API.