На данный момент, на Android есть несколько основных способов использовать базы данных:
Так уж вышло, что я фуллстэк, да еще и очень люблю котлиновскую мультиплатформу. И всё это время я был готов мириться с тем, что всякие хранения данных на JS/Web - это крайне увлекательное развлечение (нет, не увлекательное), но вот тот факт, что для JVM на серверах и для JVM на Android нужно писать разный код для баз данных, который по-сути своей делает одну и ту же работу - меня не устраивало. И так вышло, что на одном из проектов меня это допекло и я таки подключил Exposed с SQLite в проект.
Джентльменский набор
Пожалуй, начать следует с важных ссылок:
Exposed как виновник торжества
Также в проекте используется фича градла VERSION_CATALOGS для централизованного управления зависимостями из файла gradle/libs.versions.toml
Само приложение будет очень простым - мы будем иметь один экран с одним полем ввода и возможностью записать данные из этого поля в базу/прочитать оттуда. Я даже позволю себе кощунство и не буду разбивать это дело на кучу модулей, кусков условного MVVM и прочего такого, уж простите :)
Поехали
Итак, в проекте туториала есть два модуля:
lib
app
Как нетрудно догадаться, lib - это некоторая мультиплатформенная библиотека, app - наше миниприложение. В lib у нас подключены две платформы: JVM и Android. Для андроида я указал AndroidManifest с единственной строчкой-пакетом и код для инициализации базы данных, а в JVM положил нашу таблицу.
Начнем препарировать
Итак, код инициализации базы:
fun Context.initDatabase(): Database {
return Database.connect(
// "jdbc:sqlite:/data/data/app.text/database.db"
"jdbc:${SQLiteDialect.dialectName}:/data/data/${packageName}/database.db"
)
}
В качестве ресивера мы принимаем Context
- это нужно, чтобы получить впоследствие packageName
и использовать его для указания местоположения базы данных. Вообще, кусок строки /data/data/${packageName}/database.db
может быть произвольным (лишь бы приложение имело доступ к указанному месту), но рекомендуется именно /data/data/${packageName}/
, поскольку это папка приложения и вне просторов рутованных устройств к этой папке ничто кроме приложения и системы доступа не имеет.
Сам адрес базы ничем не отличается от обычного адреса, как и способ подключения.
Теперь, таблица. Для простоты я положу её условное описание, поскольку иначе это будет ~50 строк кода:
class DataTable : Table("data") {
fun put(text: String)
fun get(): String
}
Итак, это обычная Exposed таблица с функцией вставки и получения. В целом, ничего особо интересного.
То, ради чего мы все здесь собрались
Самое вкусное и важное лежит в папке jniLibs
. Фактически, это просто копия папки из Xerial SQLite и вся основная магия заключена в этих 4-х файлах .so.
Ну а дальше всё скучно
Собственно, весь тест и получившееся приложение видно на гифке выше. Каждый введенный символ вызывает сохранение в базу, каждое открытие приложения берет данные из базы.
Что по-итогу
В двух словах добавление Exposed с SQLite выглядит так:
Добавить зависимости (
exposed jdbc
,xerial sqlite jdbc
)Добавить
jniLibs
, можно в либу, хотя это не всегда хорошая идея(Опционально, если хотите использовать таблицы на JVM) - добавить в gradle dependencies андроид секции пункт
dependsOn(jvmMain)
Как итог, добавление exposed с sqlite нынче операция очень простая. Тем не менее, если есть какие-то замечания/предложения - буду рад их увидеть в комментариях.
AlexTrotsenko
Как насчёт https://github.com/cashapp/sqldelight ?
Как для Android так и JVM.
InsanusMokrassar Автор
Это другая библиотека :) выглядит она неплохо, но мне нравится строгая типизация запросов в Exposed, плюс благодаря структуре этой либы достаточно просто выделять абстракции на её базе