Что Для Вас В Orm? Полунаучный Подход К Выбору Orm Для Android

Выбор инструментов, которые так или иначе понадобятся при разработке, — один из основных подготовительных этапов при старте нового Android-проекта.

Если вы разрабатываете приложение, которое должно хранить большое количество сущностей в той или иной форме, вам не удастся избежать использования баз данных.

В отличие от коллег, занимающихся разработкой для iOS, Android-программисты не имеют удобных инструментов, упрощающих хранение объектов вроде Core Data, предоставляемых платформой (за исключением Content Provider, о том, почему он не учитывается, мы поговорим позже).

Поэтому многие Android-разработчики прибегают к использованию сторонних ORM-решений в своих проектах.

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



Что для вас в ORM? Полунаучный подход к выбору ORM для Android

Для начала хотелось бы убедиться, что выбор ORM не надуман и мы рассмотрели все доступные средства хранения данных, которые предоставляет Android SDK из коробки.

Рассмотрим их по мере возрастания сложности написания реализации такого хранилища.

Обратите внимание, что я специально не рассматривал в этом сравнении обычные файлы.

Они, конечно, идеальный вариант для любителей велосипедов, живущих по философии Not Invented Here, но в нашем случае они будут слишком низкоуровневыми.

Общие настройки http://developer.android.com/guide/topics/data/data-storage.html#pref Хранилище ключей-значений для примитивных типов данных.

Поддерживается Целое, длинное, с плавающей запятой, логическое, строковое и StringSet. Основное назначение — хранить определенное состояние приложения и пользовательские настройки.

По своей сути это оболочка XML-файла, который находится в «частной» папке вашего приложения в подкаталогеshared-prefs. Он не подходит для хранения нескольких структурированных данных одного типа.

Базы данных SQLite http://developer.android.com/guide/topics/data/data-storage.html#db SQLite — стандартная база данных в Android. Фреймворк предоставляет несколько классов-помощников, упрощающих работу с базой данных: SQLiteOpenHelper, ContentValues и т. д. Однако даже использование этих помощников не избавит вас от необходимости писать огромное количество шаблонного кода, самостоятельно следить за его созданием и модификацией.

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

Поставщик услуг http://developer.android.com/guide/topics/providers/content-providers.html Контент-провайдер — это слой поверх фактического хранилища данных.

Может показаться, что Content Provider — это «коробочная» реализация технологии ORM, но это далеко не так.

Если вы используете SQLite в качестве хранилища для контент-провайдера, вам придется самостоятельно реализовать логику создания, обновления таблиц и основных операций CRUD. В большинстве случаев использование контент-провайдера без специальных генераторов не только не сэкономит время на разработку и поддержку, но и может привести к потере гораздо большего времени, чем написание собственной реализации SQLiteOpenHelper. Однако контент-провайдер позволяет использовать некоторые удобные классы платформы, например Асинккуерихандлер , КурсорЗагрузчик , Адаптер синхронизации и другие.

Убеждаемся, что рассмотрели все доступные в Android SDK инструменты хранения данных и приходим к выводу: SQLite предоставляет все необходимые условия для организации хранения однотипных структурированных данных (удивительно, не правда ли?).

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

Именно здесь на помощь приходит техника ORM — реляционное сопоставление объектов.

Ее реализация по сути создает впечатление объектной базы данных, имеющей в своей основе обычную реляционную базу данных.

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

Определившись с технологией, обратимся с этим вопросом к Интернету и выберем 4 библиотеки:

Как правильно выбрать библиотеку и не пожалеть о своем решении, если будет поздно? В подобных статьях я встречал только качественные сравнения библиотек.

Однако, на мой взгляд, библиотека ORM должна быть сбалансирована с точки зрения удобства использования и производительности.

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

Но сначала небольшой экскурс о том, почему все же стоит обратить внимание на производительность ORM.

Для чего все это?

Зачем оценивать производительность ORM? Очевидно, что в конечном итоге все сведется к ограничениям самого SQLite, а тот, в свою очередь, к ограничениям файловой системы (речь идет об однофайловой базе данных).

Однако, как оказалось, до этих естественных ограничений еще очень далеко.

Прежде чем перейти к описанию проведенного мной теста и его результатов, хотелось бы рассказать небольшую историю о том, почему мы стали обращать внимание на производительность ORM, которую используем в наших проектах, и попытках ее улучшить.

Однажды к нашему Себбия Разработано приложение, использующее единый REST API для всех клиентов.

Из всех существующих на рынке ORM мы решили использовать ActiveAndroid, который был проверен временем и полностью нас на тот момент удовлетворял.

Основная сущность приложения (для простоты назовем ее «Сущность») — это определенное состояние множества других сущностей системы, части которых («Владельцы сущностей») были представлены только идентификаторами этих сущностей.

Предполагалось, что при запросе «Сущностей» клиент будет автоматически загружать «Владельцев сущностей», если они не найдены в кеше приложения.

В мобильных устройствах нам бы хотелось избежать такой ситуации — из-за потребления энергии на отправку нового запроса.

Любые изменения API могут привести к потенциальным проблемам совместимости с другими клиентами.

Поэтому мы решили загрузить и кэшировать список «Владельцев сущностей» до того, как возникнет необходимость загружать сами «Субъекты».

Эту операцию логичнее всего выполнить при первом запуске приложения.

Стоит отметить, что список всех «Собственников юридических лиц» был приведен полностью, а не постранично.

Каково же было наше удивление, когда мы увидели, как долго этот список хранился в базе данных! Еще раз проверив код и убедившись, что список сохраняется один раз и внутри транзакции, под наше подозрение попал ActiveAndroid. В целом причиной падения производительности приложения при сохранении большого списка стала рефлексия, а именно получение значений полей объекта и заполнение их ContentValues. Заменив код, использующий рефлексию, на код, сгенерированный самописным плагином для Eclipse, мы получили почти двукратный прирост производительности — с ~38 секунд до 20. В очередной раз убедившись, что стоит присмотреться к тому, как открываются -исходные библиотеки структурированы изнутри, перейдем к содержанию статьи.



Гонка вооружений

Из всех выбранных библиотек выделяется GreenDao — ведь это единственное среди представленных решений, использующее генерацию кода.

Чтобы не делать поспешных выводов - GreenDao самый быстрый, об остальном забудь , мы решили формализовать подход к генерации кода (используемый в описанном выше проекте в ActiveAndroid) в виде отдельного форка и пул-реквеста в официальный репозиторий, одновременно дополнив его другими полезными функциями: поддержкой «один-к- отношения «многие», «многие ко многим» и автоматическая миграция данных при изменении структуры сущностей и соответственно их таблиц.

Получившийся форк, который я для простоты назову «ActiveAndroid.Sebbia», был добавлен в тест. Пришло время рассказать о проведенном нами тесте.

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

Во вновь созданную базу данных добавляется 1000 тестовых объектов, которые после очистки кэша в памяти ORM считываются и проверяются на «правильность» данных.

Каждый предмет тестируется 10 раз, и за окончательный результат принимается среднее время выполнения.

Тестовые объекты состоят из двух текстовых полей фиксированной длины, одного поля даты и одного массива байтов, полученного из сериализуемого объекта.

Изначально предполагалось, что ORM должен сам преобразовать Serializable объект в байтовый массив, но оказалось, что ни GreenDao, ни SugarORM не имеют такой возможности, поэтому от этой идеи пришлось отказаться.

Чтобы понять максимально возможную скорость операции «объект-строка в таблице-объект», которой можно достичь стандартными средствами Android SDK, мы добавили пример использования SQLiteOpenHelper и скомпилирован SQLiteStatement .

Сам проект и все библиотеки версий, на основе которых производилось сравнение, расположен на GitHub .



Что для вас в ORM? Полунаучный подход к выбору ORM для Android

Результаты вполне предсказуемы, решение No ORM является самым быстрым, хотя и ненамного опережает GreenDAO. По большому счету код этих решений один и тот же, за исключением того, что GreenDAO предоставляет более удобный интерфейс.

В свою очередь, GreenDAO занимает второе место в общем зачете, но первое среди ORM. И это неудивительно.

GreenDAO — единственная ORM, которая полностью использует генерацию кода, скомпилированные SQLiteStatements и другие оптимизации.

Второе место среди ORM и третье место в общем зачете занимает ActiveAndroid.Sebbia, наш форк ActiveAndroid, который использует генерацию кода с помощью процессора аннотаций и SQLiteStatement. Операция записи выполнялась почти в 4 раза быстрее по сравнению с исходной конструкцией, но операция чтения была немного оптимизирована.

ActiveAndroid занимает третье место в турнирной таблице ORM, за ним следует ORMLite-ORM, пришедший в мир Android из «большой» Java, имеющий несколько плагинов для работы с разными источниками данных и достаточно простой в использовании.

На последнем месте SugarORM — самый, на мой взгляд, неудачный из рассмотренных.

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

Во-вторых, SugarORM производит впечатление очень функционально урезанного клона ActiveAndroid (отсутствие возможности конвертировать объекты других классов и адаптеров).

Ладно, с производительностью разобрались — генерация кода быстрая, рефлексия медленная.

Вызов SQliteDatabase.insert(.

) выполняется медленнее, чем вызов предварительно созданного SQLiteStatement. Но насколько удобно использовать эти библиотеки? Давайте рассмотрим каждый более подробно.



Удобства во дворе

Обзор API представленных библиотек начну с чемпиона — ГринДАО .

Как уже говорилось выше, проект довольно необычен по сравнению с другими ORM. Вместо того, чтобы самостоятельно создавать классы сущностей и указывать поля, хранящиеся в таблице, GreenDAO предлагает составлять эти классы из другого кода, полученный код генерации необходимо запускать как обычное Java-приложение.

Примерно так это выглядит:

   

public static void main(String[] args) throws Exception {

Теги: #Android #orm для android #ormlite #activeandroid #greendao #sugarorm #sqlite3 #программирование #java #Разработка мобильных приложений #Разработка Android
Вместе с данным постом часто просматривают: