Android and external database

Правильная работа с БД в 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. Здесь много мнений, разных мнений, которые Вы можете прочесть по ссылкам ниже.

Читайте также:  Fnaf sl android русификатор

Возможно, что проблемы связаны с тем, что один поток блокирует БД и второй не может к ней обратиться, возможно проблема в правах доступа к приложению(было замечено, что чаще проблемы с БД проявляются на телефонах марки НТС именно на тех моделях, которые нельзя рутануть, хотя не только на них, например на планшетах Асер), но как бы то ни было проблемы эти есть.
Я склоняюсь к варианту, что проблема в потоках, не зря ведь нам не рекомендуют вызывать методы создания базы в главном потоке.

Возможно выходом из этого будет следующее решение(рассматривается вариант №2). Используя первый вариант работы с базой, наполнить ее данными после создания, например:

Данный подход еще нужно проверить на практике, но так как этот пост нацелен на выработку верного коллективного решения по данной тематике, то комментарии и пробы на даннную тему только приветствуются.
Мораль истории такова: если вы нашли какой-то хороший кусок кода для вашего решения, то проверьте его, не поленитесь, прежде чем копипастить в свой проект.

Вцелом, данный пост показывает(касательно способа №2) как делать не надо, но и также содержит пару любопытных мыслей.
Метод getReadableDatabase() можно переопределить например так:

Кстати: следуя практике самой платформы, поле первичного ключа стоит называть «_id».

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

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

Файлик data.txt лежит в assets такой:
Zametka #1
Zametka #2
Zametka #3
Zametka #4

И класс приложения:

Отмечу, что данный класс используется только для демонстрации и проверки того, что произойдет при вызове методов getReadableDatabase()/getWritableDatabase() и создании базы. В реальных проектах код нужно адаптировать.
Кроме того в базе появилась табличка android_metadata(без моего участия), поэтому указанная выше ошибка решена.
Надеюсь кому-то пригодится.

Любопытные дополнения №1(от хабраюзера Kalobok)

Источник

Android Tutorial

Search This Blog

Android External database : Using database in «assets» folder

The best way to create a database application in android is , using an exteranal database . ie, we can create database using tools like Navicat , SQLite Browser and copy this database into our application .This method is more flexible and easy than creating a database in our application .

This is a simple application using external database file.Application will insert data into database and show data from the database in a customized list view.
Screenshots of this application are
MainActivity

you can download the source code of this project from google drive https://drive.google.com/folderview?id=0BySLpWhqmbbdY3JHMkZRZFN0bEE&usp=sharing
click on the above link ->sign into your google account ->add this to your google drive -> open it in google drive and download it.

if you crate a database file using SQlite browser it will look like this

Atfer creating a database file paste it into the assets folder of your project directory.

The main class of this project is DatabaseHeiper.java this class will copy the database file in the Assets folder into the appliction.

The functions public static Cursor rawQuery(String query) is used for select database operation,

public static void execute(String query) is used for insert. update, delete operations.
MainActivity.java
The mainAcitivy is the first activity of this sample aplication Which shows a list of registered employees.

Customized ListView is used here so Customized Adapter class(EmployeeListAdapter.java) and a bean class(EmployeeListItems.java) is used

This class is used for new employee registration . The activity is loaded when Register Here button is clicked

This Class is used to edit employee details . By Long clicking ListView items we can edit it.

Источник

Подключение существующей БД SQLite в Android Studio

Пример простого Android приложения, в котором подключаемся к заранее подготовленной базе данных SQLite.

Введение

Есть два подхода к работе с БД в Android приложениях.

Читайте также:  Gang war mafia android

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

Но данный способ не очень хорош, если, например, пишите какой-нибудь справочник или другое приложение, когда БД при установке приложения уже должна быть заполнена большим количеством записей. На мой взгляд, в этом случае лучше БД подготовить заранее, а потом уже её подключить как отдельный файл в ресурсах приложения. В данной статье рассмотрен данный случай.

Создание базы данных

Для создания БД SQLite будем использовать, например, DB Browser for SQLite. Скачиваем и устанавливаем.

Буем создавать БД с одной таблицей такого вида.

_id name age
1 Anton 30
2 Alina 24
3 Dima 28
4 Dasha 23

Итак, создаем базу данных:

Где-нибудь сохраняем и называем, например, info.db :

Создаем таблицу, например, clients . И добавляем там поле:

Первым полем у нас будет номер записи _id . Поле будет также первичным ключом:

Аналогичным способом создаем поля age и name . И жмем OK :

В списке таблиц у нас появилась наша таблица clients :

Переходим в режим заполнения таблицы:

Выбираем там нашу таблицу и жмем Добавить запись :

Заполняем наши данные и сохраняем изменения в БД:

Файл подготовленной базы данных можно взять из архива: info.zip.

Создание Android проекта

Открываем Android Studio и создаем там новый проект с пустой активностью. Всё как обычно:

Разметка активности

Так как мы создаем простейшее приложение, но в XML файле активности разместим только кнопку и поле для вывода текста:

Подготовка Java кода

Нам потребуется обработать клик на кнопку button и что-то записать в textView .

Поэтому найдем данные компоненты и свяжем их в Java коде с XML:

Объявим переменные компонентов:

Найдем компоненты в XML разметке:

Пропишем обработчик клика кнопки:

Полный код Java файла (без строчки package , которая у вас должна быть своей):

Добавление БД в проект

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

Создадим папку assets в нашем проекте:

Скопируем файл нашей базы данных:

Добавление класса для работы с БД

Для открытия и подготовки БД в Android используется наследник класса SQLiteOpenHelper . Мы тоже создадим наследник этого класса DatabaseHelper , но он будет сильно модифицированный, так как мы будем работать с готовой базой данных, а не создавать ей с помощью SQL запросов:

Ниже приведен текст всего класса, который нужно просто скопировать (не трогая свой первой строчки package ):

Для работы в последующим с другими базами данных вам ничего не нужно будет менять в данном классе, кроме строчек:

Разберем что означают эти строчки.

DB_NAME — имя файла БД. Какой файл БД вы создали, такое название сюда и копируем.

DB_PATH — путь к БД. Каждое приложение в Android имеет свою область памяти, куда складываются файлы программы. Вдруг вы захотите вывернуть путь к файлу БД. Я бы ничего не трогал.

DB_VERSION — самая интересная переменная (причем в примерах в сети по работе с готовой БД её обходят стороной). Это номер версии БД. Ниже описан принцип работы данного класса. Например, вы пишите справочник рецептов под Android и рецепты храните в БД. В момент создания установки приложения программа должна скопировать БД на устройство. Потом через какое-то время вы решили обновить приложение, и БД у вас обновилась: структура БД поменялась, добавились новые рецепты. И вам нужно заменить старую БД на новую. Вот тут вы и пропишите в данной переменной новую версию БД. И при открытии приложения будет произведена проверки версии БД, и файл БД обновится. Вначале версия БД равна 1.

Итак, логика работы класса DatabaseHelper в подготовке базы данных:

Копируем файл БД, если этого файла нет (при установке приложения).

Если номер БД обновлен, то заменяем один файл базы данных на другой:

  • После работы с базой данных из данного класса вытаскиваем экземпляр SQLiteDatabase , с которым будем работать в дальнейшем: осуществлять запросы и так далее.

Подключаемся к БД

Перейдем в класс нашей активности. В нем создадим экземпляр класса DatabaseHelper , попытаемся обновить БД, если это требуется, а потом вытащим экземпляр SQLiteDatabase .

Создадим переменные в классе:

В методе onCreate выполним подготовительные действия:

Работа с базой данных

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

Давайте при клике кнопки в textView отобразятся все имена учеников в строчку. Будем работать с помощью Cursor .

В setOnClickListener припишем такой, например, код:

Полный код Java файла активности у меня получился такой (без первой строчки package ):

Вот так приложение выглядит при запуске:

При нажатии на кнопку получим список имен из БД:

Фактически это всё. У нас есть экземпляр SQLiteDatabase mDb , с которым мы можем работать так как нам нужно. Дальше будут рассмотрены некоторые особенности работы с БД.

Обновление БД

Откроем в программе DB Browser for SQLite файл БД, который располагается в папке assets нашей программы. И внесем какие-нибудь изменения и сохраним. Я для примера поменял имя в первой строке таблицы:

Итак, в исходниках программы у нас файл БД поменялся. Запустим приложение.

И увидим, что в приложении изменения не проявились. Почему? Потому что приложение не обновляет файл БД каждый раз при запуске приложения. А вдруг вы записываете в БД какие-то записи: тогда при обновлении файла все добавленные записи сотрутся:

Нам нужно в файле класса DatabaseHelper поменять номер версии БД в сторону увеличения:

Теперь при запуске приложения данные обновятся:

Обратите внимание на то, что обновление БД произойдет только один раз. И до следующего изменения переменной DB_VERSION файл БД обновляться файлом из папки assets не будет.

Внимание! При обновлении БД заменяется файл БД, а, значит, все внесенные изменения в БД на приложении в Android (через запросы INSERT , UPDATE ) будут удалены! Поэтому, если вам внесенные изменения нужны, то не вызывайте метод updateDataBase , а в методе onUpgrade внесите стандартным способом обновления в БД. При этом замена файла БД не будет происходить. Например, так можно вставить в таблицу новый столбец:

Работа с большой БД

Когда готовил статью, то я часто встречал замечания, что файлы больше 1 Мб или 8 Мб из папки assets не копируются. Хотя, я пробовал работать с файлом в 14 Мб. Запускал на разных устройствах и никаких проблем не заметил.

Если что, то вот этот файл info_large.zip

Но мало ли. Вдруг у вас проблемы будут замечены. В качестве решения можно размещать файл БД не папке assets , а в папке res/raw :

И файл БД копируем в эту папку:

В классе DatabaseHelper нам нужно поменять только одну строчку в методе copyDBFile .

Да, если вы перед этим использовали старый вариант на том устройстве, где тестируете приложение, то не забудьте поменять версию базы данных DB_VERSION , а то вы не увидите изменений в базе данных. Можно также удалить приложение вначале, а заново его установить.

Полный код класса (без строчки package ):

Отображение списка данных по запросу

В примерах выше мы выводили информацию просто в строку в textView . Для демонстрации работы класса это достаточно, но чаще всего требуется данные из БД выводить списком. Напоследок приведу пример, когда на экран список людей из таблицы БД выведется не в строчку, а списком.

Делается это через обычный адаптер. Особенно не буду перегружать объяснением.

В activity_main.xml добавляем ListView :

Создадим файл разметки adapter_item.xml , в котором опишем внешний вид одного элемента списка с таким содержанием:

Добавим, например, в метод onCreate главной активности код:

Запускаем приложение. Видим список наших клиентов:

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

Добавление новых записей из Android приложения

В предыдущей версии статьи многие спрашивали, а как добавлять новые записи в таблицу. Абсолютно также, как и в обычном подходе в работе с базой данных. Например, вот код добавления новой записи:

И полный код примера файла активности с данным кодом (без строки package ):

Но я крайне не рекомендую добавлять новые записи в таблицу из-под Android приложения, если база данных представлена в виде файла. Так как если вы потом обновите файл базы данных в другой версии вашего приложения, то пользователь потеряет все свои данные. Либо пропишите бэкап пользовательских записей, либо используете для них вторую базу данных, созданную стандартным способом.

  • Android Studio icon.svg by Google Inc. / (2019-06-07)
  • Sqlite-square-icon.svg by Mike Toews / (2019-01-26)

Статья обновлена 2020-01-20

Пример простого Android приложения, в котором подключаемся к заранее подготовленной базе данных SQLite.

Пример простого Android приложения, в котором подключаемся к заранее подготовленной базе данных SQLite.

Источник

Читайте также:  Ошибка извлечения архива android
Оцените статью