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

  • Room

  • Родной SQLiteOpenHelper

  • Может быть, jOOQ

Так уж вышло, что я фуллстэк, да еще и очень люблю котлиновскую мультиплатформу. И всё это время я был готов мириться с тем, что всякие хранения данных на JS/Web - это крайне увлекательное развлечение (нет, не увлекательное), но вот тот факт, что для JVM на серверах и для JVM на Android нужно писать разный код для баз данных, который по-сути своей делает одну и ту же работу - меня не устраивало. И так вышло, что на одном из проектов меня это допекло и я таки подключил Exposed с SQLite в проект.

Джентльменский набор

Пожалуй, начать следует с важных ссылок:

Также в проекте используется фича градла 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 нынче операция очень простая. Тем не менее, если есть какие-то замечания/предложения - буду рад их увидеть в комментариях.

Комментарии (2)


  1. AlexTrotsenko
    20.12.2022 18:10

    Как насчёт https://github.com/cashapp/sqldelight ?

    Как для Android так и JVM.


    1. InsanusMokrassar Автор
      20.12.2022 18:15

      Это другая библиотека :) выглядит она неплохо, но мне нравится строгая типизация запросов в Exposed, плюс благодаря структуре этой либы достаточно просто выделять абстракции на её базе