Правильная работа с БД в Android
Приветствую всех дроидеров в эти непростые для нас времена.
Честно говоря, заколебала эта шумиха о патентах, войнах и т.д., но в данной статье речь пойдет не об этом.
Я не собирался писать статью на данную тему, так как везде всего полно о работе с базой данных в Android и вроде бы все просто, но уж очень надоело получать репорты об ошибках, ошибках специфичных и связанных с БД.
Поэтому, я рассматрю пару моментов с которыми я столкнулся на практике, чтобы предостеречь людей, которым только предстоит с этим разбираться, а дальше жду ваших комментариев на тему решения указанных проблем после чего внесу изменения в пост и мы сделаем отличный туториал, который будет образцом работы с SQLite в Android не только для начинающих, но и для тех, кто уже знаком с основами и написал простые приложения.
Способы работы с БД
Существует три способа работы с данными в БД, которые сразу бросаются на ум:
1) Вы создаете пустую структуру базы данных. Пользователь работает с приложением(создает заметки, удаляет их) и база данных наполняется. Примером может служить приложение NotePad в демо-примерах developer.android.com или на вашем дроид-девайсе.
2) Вы уже имеете готовую БД, наполненную данными, которую нужно распространять с приложением, либо парсите данные из файла в assets.
3) Получать данные из сети, по мере необходимости.
Если есть какой-то еще один или два способа, то с радостью дополню данный список с вашей помощью.
Все основные туториалы расчитаны как раз на первый случай. Вы пишите запрос на создание структуры БД и выполняете этот запрос в методе onCreate() класса SQLiteOpenHelper, например так:
Примерно так. Более полный вариант класса и других составляющих можно посмотреть по ссылке внизу статьи.
Дополнительно можно переопределить методы onOpen(), getReadableDatabase()/getWritableDatаbase(), но обычно хватает того, что выше и методов выборки данных.
Далее, экземпляр этого класса создаем в нашем приложении при его запуске и выполняем запросы, то бишь проблемная часть пройдена. Почему она проблемная? Потому что, когда пользователь качает приложения с маркета, то не задумывается о вашей базе данных и может произойти что угодно. Скажем сеть пропала или процесс другой запустился, или вы написали уязвимый к ошибкам код.
Кстати, есть еще один момент, на который стоит обратить внимание. Переменную экземпляра нашего класса можно создать и хранить в объекте Application и обращаться по мере необходимости, но нужно не забывать вызывать метод close(), так как постоянный коннект к базе — это тяжелый ресурс. Кроме того могут быть коллизии при работе с базой из нескольких потоков.
Но есть и другой способ, например, создавать наш объект по мере необходимости обращения к БД. Думаю это вопрос предпочтения, но который также необходимо обсудить.
А теперь самое главное. Что, если нам понадобилось использовать уже сушествующую БД с данными в приложении?
Немного погуглив, Вы сразу наткнетесь на такую «замечательную статью» — www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications в которой, как покажется, есть нужная панацея. Но не тут то было. В ней еще и ошибок несколько.
Вот они:
1) В методе createDataBase() строка:
SQLiteDatabase dbRead = getReadableDatabase();
и далее код… содержит crash приложения на НТС Desire, потому что получаем БД для чтения(она создается), но не закрывается.
Добавляем строкой ниже dbRead.close() и фикс готов, но момент спорный.
Вот что говорит дока на тему метода getReadableDatabase():
Create and/or open a database. This will be the same object returned by getWritableDatabase() unless some problem, such as a full disk, requires the database to be opened read-only. In that case, a read-only database object will be returned. If the problem is fixed, a future call to getWritableDatabase() may succeed, in which case the read-only database object will be closed and the read/write object will be returned in the future.
Like getWritableDatabase(), this method may take a long time to return, so you should not call it from the application main thread, including from ContentProvider.onCreate().
И так. Данный метод не стоит вызывать в главном потоке приложения. В остальном все понятно.
2) Ошибка: No such table android_metadata. Автор поста выкрутился, создав данную таблицу заранее в БД. Не знаю на сколько это правильный способ, но данная таблица создается в каждой sqlite-бд системой и содержит текущую локаль.
3) Ошибка: Unable to open database file. Здесь много мнений, разных мнений, которые Вы можете прочесть по ссылкам ниже.
Возможно, что проблемы связаны с тем, что один поток блокирует БД и второй не может к ней обратиться, возможно проблема в правах доступа к приложению(было замечено, что чаще проблемы с БД проявляются на телефонах марки НТС именно на тех моделях, которые нельзя рутануть, хотя не только на них, например на планшетах Асер), но как бы то ни было проблемы эти есть.
Я склоняюсь к варианту, что проблема в потоках, не зря ведь нам не рекомендуют вызывать методы создания базы в главном потоке.
Возможно выходом из этого будет следующее решение(рассматривается вариант №2). Используя первый вариант работы с базой, наполнить ее данными после создания, например:
Данный подход еще нужно проверить на практике, но так как этот пост нацелен на выработку верного коллективного решения по данной тематике, то комментарии и пробы на даннную тему только приветствуются.
Мораль истории такова: если вы нашли какой-то хороший кусок кода для вашего решения, то проверьте его, не поленитесь, прежде чем копипастить в свой проект.
Вцелом, данный пост показывает(касательно способа №2) как делать не надо, но и также содержит пару любопытных мыслей.
Метод getReadableDatabase() можно переопределить например так:
Кстати: следуя практике самой платформы, поле первичного ключа стоит называть «_id».
Пишите в комментарии свои используемые практики. Мы сделаем данный пост лучше для всех, а может и мир станет чуточку добрее.
UPD Только что проверил свой подход. Все работает в эмуляторе, но будьте осторожны.
Файлик data.txt лежит в assets такой:
Zametka #1
Zametka #2
Zametka #3
Zametka #4
И класс приложения:
Отмечу, что данный класс используется только для демонстрации и проверки того, что произойдет при вызове методов getReadableDatabase()/getWritableDatabase() и создании базы. В реальных проектах код нужно адаптировать.
Кроме того в базе появилась табличка android_metadata(без моего участия), поэтому указанная выше ошибка решена.
Надеюсь кому-то пригодится.
Любопытные дополнения №1(от хабраюзера Kalobok)
Источник
MS Access на Android
MS Access для android
Здравствуйте! Подскажите, пожалуйста, есть ли программы для android (планшет и т.п.), в которых.
Android Debug Bridgre Root access
Здравствуйте. Запускаю adb devices, вижу, что в списке есть мой LG P705, после этого запускаю adb.
RAD Studio Android — ошибка access violation в программе
Здравствуйте форумчане! Вопрос созрел такой: Отлаживаю прогу в RAD Studio 10.1. Сначала под.
Ошибка Access violation at addr. во время работы приложения на Android
Уважаемые форумчяне, может ли кто нибудь подсказать мне о причинах и методах борьбы со следующей.
http://www.androidz.ru/bazy-da. 14280.html
написано, что аналоги. больше ничего не встречал
в закладках было. если полезно, то отпишись, если нет, то все равно отпишись))
планшетника пока нет, но планирую приобрести)
Насколько мне известно, нет.
Если же стоит вопрос об использовании функционала Аксесс на планшете, то единственный известный мне вариант — Аcer W 500, 501. На андроиде же и в «облаках» работать не будет.
Можно виртуализировать Винд на андроиде, но это будет трудоёмко (и может не получиться вообще) и очень медленно работать. Ещё вариант — дождаться выхода W8, обещанной в кач универсальной платформы (и то есть принципиальные ньюансы).
По поводу аналогов не скажу, но предполагаю, что чем больше кода задействовано в приложении, тем корректный перевод на . nix-платформы, например, тот же Андроид, невозможнее
Источник
View MS Access DB 1.5.9
(Просмотр MS Access DB)
Скачать
Тут вы можете скачать АПK-файл «com.kmsoft.access_db_viewer» для Андроид бесплатно, апк файл версии — 1.5.9 для загрузки на ваш андроид просто нажмите эту кнопку. Это просто и безопасно. Мы предоставляем только оригинальные апк файлы. Если какой-либо из материалов на этом сайте нарушает ваши права, сообщите нам
********** Средство просмотра базы данных Access для Android **********
позволяет вам открыть базу данных Open Access для Android (формат ACCDB или MDB (Jet).), Чтобы
открывать строки таблицы с разбиением на страницы , Сортировка и фильтрация,
Поддержка всех версий базы данных ms Access
* Microsoft Access 2000, 2003, 2007, 2010, 2013 2016
Особенности
• Открыть все версии базы данных ms Access
• Открыть базу данных ACCDB или базу данных MDB.
• открыть данные таблицы со списком подкачки.
• Фильтр по данным определенного столбца (с множеством опций)
• Сортировка данных таблицы по столбцу
• Просмотр формы
сведений о строках • Поддержка большой базы данных (протестировано на 350 МБ 2,5 миллиона строк).
• Открыть зашифрованную базу данных с помощью пароля
• Просмотр взаимосвязей записей
• Открыть облачную базу данных, щелкнув по файлу
Примечания:
Это приложение не поддерживает вставку данных, редактирование данных и удаление строк, а также не отображает запросы и формы
(я работаю над этим) .
Источник
Скачать программы Viewer for MS Access Database (ACCDB APK
Просмотреть файл MS Access DB (ACCDB — MDB — DB) Открыть таблицу данных Пейджинговая фильтрация Сортировать.
Описание: Km4Dev
********** программа для просмотра базы данных Access для Android **********
позволяет открыть доступ к базе данных для Android (ACCDB или формат MDB (Jet).) в
открытых Ряды столов с пейджинга, сортировки и фильтрации,
* Базы данных Microsoft Access 2000
* Базы данных Microsoft Access 2002
* Базы данных Microsoft Access 2003
* Базы данных Microsoft Access 2007
* Базы данных Microsoft Access 2010
* Базы данных Microsoft Access 2013
* Базы данных Microsoft Access 2016
Особенности
• Открыть все версии MS Access базы данных
• открытая ACCDB базы данных или базы данных MDB.
• открыть таблицу данных со списком подкачки.
• Фильтр на конкретных данных столбца (с большим количеством опций)
• Сортировка данных таблицы по столбцу
• Просмотр строки Detail Form
• поддержка большая база данных (испытано на 350MB 2,5 миллиона строк).
• Открыть базу данных шифруют с паролем
• Просмотр записи отношения
• открыть базу данных облака щелчком на файле
Заметки:
Это приложение не поддерживает Вставить данные, редактировать данные и удалять строки, также не отображает запросы и формы
(Я работаю над этим).
Источник
Как я создаю базу данных для своих приложений
Если в нашем приложении больше 5 таблиц, то уже было бы не плохо использовать какой-нибудь инструмент для визуального проектирования архитектуры БД. Поскольку для меня это хобби, то и использую я абсолютно бесплатный инструмент под названием Oracle SQL Developer Data Modeler (скачать его можно тут).
Данная программа позволяет визуально рисовать таблицы, и строить взаимосвязи с ними. Многие ошибки проектирования архитектуры БД можно избежать при таком подходе проектирования (это я уже вам говорю как профессиональный программист БД). Выглядит это примерно так:
Спроектировав саму архитектуру, приступаем к более нудной части, заключающийся в созданий sql кода для создания таблиц. Для помощи в этом вопросе, я уже использую инструмент под названием SQLiteStudio (его в свою очередь можно скачать тут тут).
Данный инструмент является аналогом таких известных продуктов как SQL Naviagator, Toad etc. Но как следует из названия, заточен он под работу с SQLite. Он позволяет визуально создать БД и получить DDL код создаваемых таблиц. Кстати, он также позволяет создавать представления (View), которые вы тоже при желании можете использовать в своем приложении. Не знаю насколько правильный подход использования представлений в программах для Android, но в одном из своих приложений я использовал их.
Собственно говоря я больше не каких сторонних инструментов не использую, и дальше начинается магия с Android Studio. Как я уже писал выше, если начать внедрять SQL код в Java код, то на выходе мы получим плохочитаемый, а значит и плохо расширяемый код. Поэтому я выношу все SQL инструкции во внешние файлы, которые у меня находятся в директории assets. В Android Studio выглядит это примерно так:
Теперь давайте посмотрим на код внутри моего DBHelper который я использую в своих проектах. Сначала переменные класса и конструктор (тут без каких либо неожиданностей):
Теперь метод onCreate и тут становится уже интереснее:
Логически он разделен на два цикла, в первом цикле я получаю список SQL — инструкций для создания БД и затем выполняю их, во втором цикле я уже заполняю созданные ранее таблицы начальными данными. И так, шаг первый:
Тут все достаточно просто, мы просто читаем содержимое файлов, и конкатенируем содержимое каждого файла в элемент массива. Обратите внимание, что я произвожу сортировку списка файлов, так как таблицы могут иметь внешние ключи, а значит таблицы должны создаваться в определенном порядке. Я использую нумерацию в название файлов, и с помощью нею и произвожу сортировку.
С заполнением таблиц все веселей. Таблицы у меня заполняются не только жестко заданными значениями, но также значениями из ресурсов и UUID ключами (я надеюсь когда-нибудь прийти к сетевой версии своей программы, что бы мои пользователи могли работать с общими данными). Сама структура файлов с начальными данными выглядит так:
Несмотря на то, что файлы у меня имеют расширение sql, внутри не sql код а вот такая штука:
prioritys
pri_id:UUID:UUID
pri_object:string:object_task
pri_name:string:normal
pri_color:color:colorGreen
pri_default:int:1
prioritys
pri_id:UUID:UUID
pri_object:string:object_task
pri_name:string:hold
pri_color:color:colorBlue
pri_default:int:0
prioritys
pri_id:UUID:UUID
pri_object:string:object_task
pri_name:string:important
pri_color:color:colorRed
pri_default:int:0
prioritys
pri_id:UUID:UUID
pri_object:string:object_project
pri_name:string:normal
pri_color:color:colorGreen
pri_default:int:1
prioritys
pri_id:UUID:UUID
pri_object:string:object_project
pri_name:string:hold
pri_color:color:colorBlue
pri_default:int:0
prioritys
pri_id:UUID:UUID
pri_object:string:object_project
pri_name:string:important
pri_color:color:colorRed
pri_default:int:0
Структура файла такая: я выполняю вызов функции split(«:») применительно к строчке и если получаю что ее размер равен 1 то значит это название таблицы, куда надо записать данные. Иначе это сами данные. Первое поле это название поля в таблице. Второе поле тип, по которому я определяю что мне надо в это самое поле записать. Если это UUID — это значит мне надо сгенерировать уникальное значение UUID. Если string значит мне надо из ресурсов вытащить строковое значение. Если color, то опять-таки, из ресурсов надо вытащить код цвета. Если int или text, то я просто преобразую данное значение в int или String без каких либо телодвижений. Сам код выглядит вот так:
Источник