Images sqlite что за файл
В первой части мы изучили возможности SQLite. Теперь нужно научиться подключать базу данных в приложении на Android.
SQLite зарекомендовала себя в качестве чрезвычайно надёжной системы баз данных, которая используется во многих бытовых электронных устройствах и программах, включая некоторые MP3-проигрыватели, iPhone, iPod Touch, Mozilla Firefox и др.
С помощью SQLite вы можете создавать для своего приложения независимые реляционные базы данных. Android хранит базы данных в каталоге /data/data//databases на эмуляторе, на устройстве путь может отличаться. По умолчанию все базы данных закрытые, доступ к ним могут получить только те приложения, которые их создали.
Каждая база данных состоит из двух файлов. Имя первого файла базы данных соответствует имени базы данных. Это основной файл баз данных SQLite, в нём хранятся все данные. Вы будете создавать его программно. Второй файл — файл журнала. Его имя состоит из имени базы данных и суффикса "-journal". В файле журнала хранится информация обо всех изменениях, внесенных в базу данных. Если в работе с данными возникнет проблема, Android использует данные журнала для отмены (или отката) последних изменений. Вы с ним не будете взаимодействовать, но если вы будете просматривать внутренности своего устройства, то будете знать, зачем этот файл там присутствует.
Выборка данных из базы SQLite с помощью JOIN
Нельзя использовать метод SQLiteDatabase query() для выполнения запроса к нескольким таблицам. Для этого нужно составить собственный SQL-запрос . В приведенном ниже примере запрос определяется в классе SampleDBContract :
Обратите внимание, что в условии WHERE мы используем символ « ? ». Чтобы не нарушить синтаксис SQL нужно определить selectArgs String [] со значениями, которые будут заменять в предоставленном SQL-запросе символ « ? »:
rawQuery()
Также существует метод rawQuery(), принимающий сырой SQL-запрос.
Метод rawQuery() - это сырой запрос, как есть, т.е. пишется строка запроса, как это обычно делается в SQL. Пример выглядит следующим образом:
Класс SQLiteQueryBuilder - удобный способ для построения запросов. Выбор за вами!
Контент-провайдеры
Контент-провайдеры поддерживают стандартный синтаксис запросов для чтения, изменения, вставки и удаления данных. Если необходимо предоставить доступ к своим данных для других приложений, существует два варианта:
- создать собственный контент-провайдер, как подкласс класса ContentProvider;
- добавить данные к существующему провайдеру — если уже есть провайдер, который управляет теми же данными, и вы имеете разрешение для работы с этими данными.
Отображение содержимого объекта Cursor в RecyclerView
Cursor предоставляет произвольный доступ к набору результатов, возвращаемому запросом к базе данных. Это означает, что через Cursor можно получить доступ к значениям в любом месте, подобно Java-спискам или массивам. Благодаря этому приему можно реализовать RecyclerView с использованием Cursor так же, как мы реализуем RecyclerView с помощью ArrayLists . Вместо вызова List.get(i) , вы перемещаете Cursor в нужную позицию, используя moveToPosition() . После этого вызываете соответствующий метод getXXX(int columnIndex) , где XXX - это Blob , Double , Float , Int , Long , Short или String .
Чтобы не беспокоиться о корректных индексах столбцов из метода readFromDB() , примененного выше, мы используем метод getColumnIndexOrThrow() , который извлекает индекс указанного столбца или генерирует исключение, если имя столбца не существует внутри объекта Cursor :
Работа с SQLite
Создание базы данных: Для того чтобы создать новую базу данных необходимо воспользоваться функцией sqlite_open(). Если базы, имя которой указано в параметре "filename" не существует, то функция создаст новую базу данных с именем "filename" и вернёт идентификатор базы данных.
В этом руководстве я подробно расскажу о том, как использовать базу данных Android SQLite .
Описание примера приложения
В нашем Android SQLite примере мы создадим две таблицы: Employer и Employee . Таблица Employee будет содержать ссылку на внешний ключ таблицы Employer . Мы рассмотрим, как вставлять, выбирать, обновлять и удалять строки из таблиц. Я также продемонстрирую, как вывести элементы, выбранные из базы данных SQLite в RecyclerView ( список ) и в Spinner .
У нас есть MainActivity , из которого можно перейти к EmployerActivity ( для работы с таблицей Employer ) или к EmployeeActivity ( для работы с таблицей Employee ):
Классы хранения базы данных SQLite
Классы определяют то, как данные хранятся в базе. SQLite сохраняют значения с помощью пяти доступных классов хранения:
- NULL - нулевое значение;
- INTEGER - для целых чисел, содержащих от 1 до 8 байтов;
- REAL - числа с плавающей запятой;
- TEXT - текстовые строки, хранящиеся с использованием кодировки базы данных ( UTF-8 или UTF-16 );
- BLOB - двоичные данные, хранящиеся точно так, как они были введены.
Создание базы данных с помощью SQLiteOpenHelper
Самый простой способ управления созданием базы данных и версиями - создать подкласс SQLiteOpenHelper . Он упрощает управление базой данных SQLite , создавая БД, если они не существуют. Необходимо только переопределить методы onCreate() и onUpgrade() , чтобы указать нужное действие для создания или обновления базы данных:
Теперь в нашем примере Android database SQLite задаем для нашей базы данных SQLite имя ( sample_database ). Конструктор вызывает конструктор суперкласса с именем и версией базы данных. В onCreate мы указываем объекту SQLiteDatabase выполнить оператор Employer CREATE_TABLE SQL . Через onUpgrade мы сбрасываем таблицу Employer и создаем ее снова:
Таблица Employer имеет три столбца: name , description и founded_date . Нажатие кнопки сохранения вызывает метод saveToDB() :
В saveToDB() мы получаем ссылку на объект SQLiteDatabase , используя метод getWritableDatabase() из SQLiteOpenHelper . Этот метод создает базу данных, если она еще не существует, или открывает ее, если она уже создана. GetWritableDatabase возвращает объект SQLiteDatabase , который открывает доступ на чтение / запись:
В приведенном выше фрагменте кода есть четыре момента:
- Мы получаем объект SQLiteDatabase , который открывает доступ на запись в базу данных;
- Значения, которые будут храниться в базе данных, помещаются в объект ContentValue с именем столбца в качестве ключа;
- Мы помещаем Date в объект ContentValue , который переводится в класс хранения данных Android SQLite INTEGER ;
- При вставке строки в базу данных с помощью метода database.insert() возвращается идентификатор строки.
Класс ContentValues
Класс ContentValues используется для добавления новых строк в таблицу. Каждый объект этого класса представляет собой одну строку таблицы и выглядит как ассоциативный массив с именами столбцов и значениями, которые им соответствуют.
В заключении
Полная версия исходного кода доступна на github для использования и изменения. Базы данных Android SQLite - это мощное средство, доступное для всех мобильных приложений.
Пожалуйста, оставьте ваши мнения по текущей теме материала. Мы крайне благодарны вам за ваши комментарии, отклики, лайки, дизлайки, подписки!
Пожалуйста, оставляйте ваши комментарии по текущей теме материала. За комментарии, подписки, отклики, лайки, дизлайки огромное вам спасибо!
Изучим SQLite с самых основ. Для начала мы научимся работать с SQLite без привязки к Android. Это позволит вам набить руку, лучше узнать её возможности. После этого будет легче интегрировать базу данных в Android.
Если вы знакомы с SQL, например, MySQL, то многое будет понятным. Я буду ориентироваться на новичков.
База данных нужна для долгого хранения большого количества данных, которые не пропадут после закрытия приложения. Кроме того, база данных на основе SQL позволяет производить различные манипуляции по выборе - найти самого толстого котика, найти самого молодого кота, найти только котов и только кошек и т.д.
Чтобы было легче понять принцип работы с базой данных, представьте себе следующую аналогию. Допустим на диске вы создали новую папку - это аналог базы данных. В новой папке вы можете создать несколько текстовых файлов с информацией (рецепты, дни рождения, список гостей) - это таблицы базы данных.
Таблица - это важная часть базы данных. Информация в таблицах упорядочена, чтобы её можно быстро найти. Таблица состоит из вертикальных столбцов (column) и горизонтальных рядов (row).
Мы построили новый пятизвёздочный отель с уникальным названием "Кошкин дом". Нам требуется учёт всех постояльцев гостиницы. Без базы данных не обойтись. Создадим базу данных hotel с таблицей guests, в которой будут столбцы name (имя), city (город), gender (пол), age (возраст).
Первый способ. Метод query()
Извлечение данных происходит через метод query(). Данные хранятся в наборе строк, которые можно представить в виде таблицы. Из этой таблицы вы уже можете извлечь конкретное значение.
У метода query() множество параметров. В первом параметре укажите имя таблицы, во втором - массив имён колонок, далее идут дополнительные условия. Пока везде оставим null. В нашем примере мы добавили одну запись и извлечь её просто.
Метод query()
Для чтения данных используют вызов метода query():
В метод query() передают семь параметров. Если какой-то параметр для запроса вас не интересует, то оставляете null:
- table — имя таблицы, к которой передается запрос;
- String[] columnNames — список имен возвращаемых полей (массив). При передаче null возвращаются все столбцы;
- String whereClause — параметр, формирующий выражение WHERE (исключая сам оператор WHERE). Значение null возвращает все строки. Например: _id = 19 and summary = ?
- String[] selectionArgs — значения аргументов фильтра. Вы можете включить ? в "whereClause"". Подставляется в запрос из заданного массива;
- String[] groupBy - фильтр для группировки, формирующий выражение GROUP BY (исключая сам оператор GROUP BY). Если GROUP BY не нужен, передается null;
- String[] having — фильтр для группировки, формирующий выражение HAVING (исключая сам оператор HAVING). Если не нужен, передается null;
- String[] orderBy — параметр, формирующий выражение ORDER BY (исключая сам оператор ORDER BY). При сортировке по умолчанию передается null.
Объект Cursor, возвращаемый методом query(), обеспечивает доступ к набору записей результирующей выборки. Для обработки возвращаемых данных объект Cursor имеет набор методов для чтения каждого типа данных — getString(), getInt() и getFloat().
Чтобы получить все записи из нужных столбцов без условий, достаточно указать имя таблицы в первом параметре и строчный массив во втором. В остальных параметрах оставляем null:
Для запроса с условием используются третий и четвёртый параметр. Например, нам нужны записи, у которого имя кота будет Барсик:
Параметр "NAME = ?" означает, что столбец NAME должен содержать значение, указанное следующем параметре.
Множественные условия. Об этом говорилось выше.
Пример при использовании числовых значений, например, идентификатор первичного ключа (об этом тоже говорилось)
Для сортировки используется последний параметр. Нужно указать нужный столбец, по которому будет проводиться сортировка. По алфавиту с буквы A - ASC, наоборот - DESC
Возможна сортировка по нескольким столбцам.
Вы можете использовать функции SQL для составления запросов: AVG(), COUNT(), SUM(), MAX(), MIN() и др.
Ещё один абстрактный пример подсчёта средней суммы:
sqlite3.exe
Давайте изучать SQLite. Начнём с командной строки под Windows. Хорошая новость - ничего не надо скачивать. Когда вы устанавливали инструменты разработки Android, то в папке SDK\platform-tools уже есть исполняемый файл sqlite3.exe. Для удобства я создал новую папку sqlite для опытов и скопировал туда этот файл.
Если сейчас запустить исполняемый файл, то увидим следующее окно.
В окне выводится подсказка, что для работы с базой данных нужно набрать команду .open FILENAME. Вводим:
В папке рядом с sqlite3.exe появится новый файл hotel.db.
Далее в окне наберите команду .help для просмотра всех команд. Затем введите команду .quit , чтобы закрыть программу.
Теперь запустите отдельно командную строку и введите команду sqlite3 hotel.db .
Вы открыли базу данных hotel и программа выводит приглашение sqlite> для ввода специальных команд.
Прежде чем заполнять базу новыми данными, нужно ознакомиться с используемыми типами данных в SQLite:
- NULL - пустое значение
- INTEGER - целое число
- REAL - дробное число
- TEXT - строка
- BLOB - для изображений и бинарных файлов
Как видите, в SQLite не используются булевы типы. Поэтому для таких случаев используется тип INTEGER со значениями 0 для false и 1 для true.
Также для оптимизации используйте INTEGER вместо TEXT там, где это возможно. Например, для номерного фонда вы можете использовать значения 0, 1, 2, 3 вместо описания "одноместный", "двухместный", "люкс" и т.д.
Вернёмся к приглашению sqlite> и введём команду .tables . Так как у нас нет таблиц, то ничего не выводится. Запомним эту команду.
Обновление SQLiteOpenHelper
На данный момент в Android Studio SQLite у вас должна быть создана таблица Employer и в нее добавлены значения. Если вы не изменяете версию базы данных, новая таблица Employee не будет создана. К сожалению, если вы измените версию через повторный вызов метода onUpgrade() , то таблица Employer будет сброшена. Чтобы предотвратить это, можно закомментировать или удалить оператор drop в методе onUpgrade() и добавить оператор execSQL() для создания таблицы Employee . Поскольку таблица Employee ссылается на таблицу Employer , сначала необходимо создать таблицу Employer :
Метод insert()
Для вставки новой записи в базу данных SQLite используется метод insert():
В метод insert() необходимо передать три параметра:
- table — имя таблицы, в которую будет вставлена запись;
- nullColumnHack — в базе данных SQLite не разрешается вставлять полностью пустую строку, и если строка, полученная от клиента контент-провайдера, будет пустой, то только этому столбцу явно будет назначено значение null;
- values — карта отображений (класс Map и его наследники), передаваемая клиентом контент-провайдера, которая содержит пары ключ-значение. Ключи в карте должны быть названиями столбцов таблицы, значения — вставляемыми данными.
Метод insert() возвращает идентификатор _id вставленной строки или -1 в случае ошибки.
Для создания новой строки понадобится объект ContentValues, точнее, его метод put(), чтобы обеспечить данными каждый столбец. Объект ContentValues представляет собой пару name/value данных. Вставьте новую строку, передавая в метод insert(), вызванный в контексте нужной нам базы данных, имя таблицы и объект ContentValues
Внедрение опасного кода
При работе с базой данной надо следить за безопасностью данных. Опытный пользователь может удалить базу. На своём устройстве он делать этого может и не будет, но на устройстве жертвы вполне.
Простой вариант атаки. Допустим у нас есть поле для ввода идентификатора, чтобы узнать информацию о госте. Нормальный пользователь введёт число "3" для поиска третьего гостя. В коде это будет следующим образом.
Тогда идентификатор будет _ID == 2;.
Хакер может ввести следующую строку в текстовое поле:
В коде это превратится в следующее:
Таким образом вредитель внедрил нежелательный код, который удалит таблицу.
SQLite – это реляционная база данных, запросы к которой можно осуществлять при помощи языка запросов SQL. База данных не поддерживает все особенности SQL и уступает в функциональности другим развитым СУБД, но вполне подходит для хранения и извлечения информации.
Классы для работы с SQLite
Работа с SQLite напрямую теперь считается устаревшим подходом. На Google I/O 2017 был представлен новых механизм доступа к базе данных через специальную обёртку Room
Работа с базой данных сводится к следующим задачам:
- Создание и открытие базы данных
- Создание таблицы
- Создание интерфейса для вставки данных (insert)
- Создание интерфейса для выполнения запросов (выборка данных)
- Закрытие базы данных
Метод update()
Для обновления и удаления записей в базе данных используют соответственно методы update() и delete():
В этих методах два последних параметра формируют SQL-выражение WHERE аналогично рассмотренному методу query() для чтения данных. Эти методы возвращают число модифицированных или удаленных строк.
Обновление строк также происходит с помощью класса ContentValues. Создайте новый объект ContentValues, используя метод put() для вставки значений в каждый столбец, который вы хотите обновить. Вызовите метод update() в контексте базы данных, передайте ему имя таблицы, обновленный объект ContentValues и оператор WHERE, указывающий на строку (строки), которую нужно обновить.
В первом параметре метода мы указываем имя таблицы, которую хотим обновить.
Во втором параметре мы указываем значение, которое хотим обновить. Например, в колонке "DESCRIPTION" нужно обновить значение на "Clever".
В третьем параметре указывается условие для обновления. Выражение "NAME = ?" означает, что колонка NAME должна быть равна указанному значению. Знак вопроса является подстановочным символом и из четвёртого параметра берётся нужное значение.
Обратите внимание, что последний параметр является массивом. Вы можете использовать множественные условия для запроса. Например, нам нужно обновить запись в таблице, используя сразу две колонки для составления условия.
Данный код соответствует выражению Where NAME = "Murzik" or DESCRIPTION = "Nice".
Для условий всегда используются строки, поэтому может понадобиться конвертация в некоторых случаях. Например, нужно использовать идентификатор таблицы со значением 1.
Если в последних двух параметрах использовать null, то будут обновлены все записи в таблице.
SQLiteDatabase
Для управления базой данных SQLite существует класс SQLiteDatabase. В классе SQLiteDatabase определены методы query(), insert(), delete() и update() для чтения, добавления, удаления, изменения данных. Кроме того, метод execSQL() позволяет выполнять любой допустимый код на языке SQL применимо к таблицам базы данных, если вы хотите провести эти (или любые другие) операции вручную.
Каждый раз, когда вы редактируете очередное значение из базы данных, нужно вызывать метод refreshQuery() для всех курсоров, которые имеют отношение к редактируемой таблице.
Для составления запроса используются два метода: rawQuery() и query(), а также класс SQLiteQueryBuilder.
Отображение данных из запроса SQLite в Spinner
Чтобы создать работника в таблице Employee , пользователю необходимо выбрать соответствующего работодателя в таблице Employer . Для этого можно предоставить пользователю Spinner . Отобразить содержимое Cursor в Spinner довольно просто.
Сначала мы выполняем Android SQLite query , как было описано выше, выбираем только name из Employer и id (queryCols) . Затем создаем экземпляр SimpleCursorAdapter , передавая ему Cursor , массив столбцов для отображения ( adapterCols ) и массив представлений, с помощью которых должны отображаться столбцы ( adapterRowViews ). Затем устанавливаем Spinner Adapter для SimpleCursorAdapter :
Первый способ. ContentValues
Для вставки сначала подготавливаются данные с помощью класса ContentValues. Вы указываете имя колонки таблицы и значение для неё, т.е. работает по принципу "ключ-значение". Когда подготовите все данные во все столбцы, то вызывайте метод insert(), который сразу раскидает данные по столбцам.
Способ очень удобен, требует мало кода и легко читаем. Вы создаёте экземпляр класса, а затем с помощью метода put() записываете в нужную колонку нужные данные. После чего вызывается метод insert(), который помещает подготовленные данные в таблицу.
У метода insert() три аргумента. В первом указывается имя таблицы, в которую будут добавляться записи. В третьем указывается объект ContentValues, созданный ранее. Второй аргумент используется для указания колонки. SQL не позволяет вставлять пустую запись, и если будет использоваться пустой ContentValue, то укажите во втором аргументе null во избежание ошибки.
Метод delete()
Чтобы удалить строку, просто вызовите метод delete() в контексте базы данных, указав имя таблицы и оператор WHERE. В результате вы получите строки, которые хотите удалить:
Кроме вышеперечисленных методов, в этом классе также определены различные методы для выполнения других общих задач управления базой данных.
Наполняем базу данных
Создадим вспомогательный метод для вставки записи в базу данных. Для этого считываем данные, которые вводятся в текстовые поля, а далее по предыдущему учебному примеру.
Метод вызывается в меню для значка с галочкой, которая выводится на панели действия активности.
Запускаем проект и проверяем работу кода.
Работаем с записями базы данных
Чтобы проверить работоспособность базы данных, в главной активности поместим вспомогательный метод displayDatabaseInfo() для отображения информации.
Массив projection - это список столбцов, которые нас интересуют. В SQL-запросе мы их указываем в операторе SELECT:
В методе query() третий и четвёртый параметр определяют условие WHERE. Возьмём случай с выражением:
В коде такое выражение выглядело бы так.
Как видим, в знак вопроса подставляется нужное значение.
Последний аргумент отвечает за сортировку по возрастанию или убыванию. Например, по возрасту.
Второй способ. Метод rawQuery()
Второй способ использует сырой (raw) SQL-запрос. Сначала формируется строка запроса и отдаётся методу rawQuery().
Запустите проект. При запуске создаётся база данных. Убедиться в этом можно, если запустить Android Device Monitor. Выберите вкладку File Explorer и найдите своё приложение (на эмуляторе). Вы увидите, что появилась папка data/data/имя_пакета/databases с файлом hotel.db. Метод getReadableDatabase создаёт или открывает базу данных.
Сейчас мы увидим, что пока у нас 0 гостей.
Небольшое предупреждение. При работе с базой данных мы обращаемся к файлу. Если база данных очень большая, то запросы не будут мгновенными. Операции с файлами являются медленными, поэтому следует использовать многопоточность. Для наших примеров это не страшно, поэтому мы пока не будем усложнять код.
Установка SQLite
В PHP5 поддержка SQLite установлена и включена по умолчанию.
Установка под Windows: Для установки SQLite необходимо скачать и скопировать в папку с расширениями библиотеку "php_sqlite.dll", которую можно загрузить по ссылке: http://snaps.php.net/win32/PECL_STABLE/php_sqlite.dll. Затем необходимо раскомментировать (или добавить) строку "extension=php_sqlite.dll" в файле "php.ini". Для нормального функционирования SQLite также необходимо раскомментировать строку "extension=php_pdo.dll".
Если используется полная версия PHP в zip-архиве, а не в виде инсталлятора, соответствующие библиотеки расширения должны находится в директории ext. Подробнее можно почитать в статье Установка Apache, PHP, MySQL.
Библиотека "php_pdo.dll" должна загружаться до загрузки "php_sqlite.dll". То есть в php.ini строка "extension=php_sqlite.dll" должна стоять после "extension=php_pdo.dll".
Установка под Unix: Скачайте свежую версию SQLite с официального сайта ( http://sqlite.org/download.html ). Прочтите файл "INSTALL", поставляемый с исходными тестами модуля. Или просто воспользуйтесь командой установки PEAR: "pear install sqlite".
Выбор данных из базы данных SQLite
Подобно тому, как мы применили метод getWritableDatabase() , можно вызвать getReadableDatabase() объекта SQLiteOpenHelper для получения объекта SQLiteDatabase , который можно использовать для чтения информации из базы данных. Стоит отметить, что объект SQLiteDatabase , возвращаемый getReadableDatabase() , предоставляет собой тот же самый доступ на чтение / запись в базу данных, который был возвращен функцией getWritableDatabase() , за исключением тех случаев, когда существуют определенные ограничения. Например, файловая система, содержащая заполненную базу данных, и база данных может быть открыта только для чтения.
Метод readFromDB будет запрашивать БД, и возвращать все строки из таблицы Employer , в которых имя или описание из таблицы Employer совпадает со значением, введенным в EditText . А также строки, в которых дата основания компании совпадает со значением, введенным в EditText :
В коде Android SQLite query , приведенного выше, projection является массивом String , представляющим столбцы, которые мы хотим получить. selection является строковым представлением условия SQL WHERE , отформатированным таким образом, что символ '?' будет заменен аргументами в массиве selectionArgs String . Вы также можете группировать, фильтровать и сортировать результаты запроса. Вставка данных в базу SQLite с использованием описанного выше метода защищает от SQL-инъекций .
Обратите внимание на объект, возвращаемый запросом - Cursor . В следующем разделе мы покажем, как вывести содержимое Cursor с помощью RecyclerView .
Определение таблиц
Поскольку база данных SQLite является локальной, нужно обеспечить, чтобы приложение создавало таблицы и по мере необходимости сбрасывало их.
Начнем с Android SQLite query создания таблицы Employer , а затем перейдем к EmployerActivity .
Рекомендуется размещать логику создания базы х SQLite в классе. Это облегчает устранение возможных неполадок. Назовем наш класс SampleDBContract :
Мы определяем частный конструктор для SampleDBContract , а затем создаем класс для представления таблицы Employer . Обратите внимание: класс Employer реализует интерфейс BaseColumns . Он предоставляет два столбца в нашей таблице. Это столбец _ID , который будет автоматически увеличиваться при добавлении каждой новой строки. И столбец _COUNT , который может использоваться ContentProviders для возврата количества записей, извлекаемых через запрос. Столбец _COUNT не является обязательным. Строка CREATE_TABLE компилируется в следующий оператор SQL :
На данный момент в нашем Android SQLite примере мы определили схему таблицы Employer .
Второй способ. SQL-запрос
Существует также другой способ вставки через метод execSQL(), когда подготавливается нужная строка и запускается скрипт. Этот способ возможно понравится PHP-кодерам, которые привыкли к такому синтаксису.
Научившись вставлять данные, можно заняться второй активностью, которая и предназначена для этих целей.
Чтение данных
Считывать данные также можно двумя способами. В любом случае результат возвращается в виде объекта Cursor. Не путайте его с курсором мыши, который бегает у вас на экране.
Удаление данных
Также не реализовано. Проделайте самостоятельно.
Метод delete() класса SQLiteDatabase работает по тому же принципу, как и метод update(). Он имеет следующую форму:
Изменение данных
Обновление не реализовано в программе, проделайте это самостоятельно.
Если запись уже существует, но вам нужно изменить какое-то значение, то вместо insert() используйте метод update(). В остальном принцип тот же. Предположим, что повторном осмотре котёнка выяснилось, что это кот, а не кошка. Если вы уже назвали котёнка Муркой, то логично назвать его теперь Мурзиком. Вызываем метод put(), а затем обновляем запись в базе данных.
Первый параметр метода update() содержит имя таблицы. Второй параметр указывает, какие значения должны использоваться для обновления. Третий параметр задает условия отбора обновляемых записей (WHERE). В приведенном примере "NAME = ?" означает, что столбец NAME должен быть равен некоторому значению. Символ ? обозначает значение столбца, которое определяется содержимым последнего параметра. Если в двух последних параметрах метода передаётся значение null, будут обновлены ВСЕ записи в таблице.
Возможны и сложные условия.
Если столбец не является строкой, то его нужно преобразовать в строку, чтобы использовать в качестве условий.
Будьте осторожны с обновлениями. Если в последних двух параметрах передать значение null, то будут обновлены все записи в таблице, так как в запросе нет условий.
Вставляем картинки в базу
Вставлять картинки в базу данных не самая лучшая идея. Оставлю только для ознакомления. Так как SQLite не работает с изображениями напрямую, то нужно сконвертировать картинку в байтовый массив. А при извлечении нужно проделать обратную задачу - из байтового массива воссоздать изображение. Создадим вспомогательный класс.
Создадим таблицу следующим образом. Переменная DATABASE_TABLE - строковая константа.
Вставка внешнего ключа в базу данных
Вставка строки, содержащей внешний ключ, полностью идентична вставке строк в таблицу без ограничений по внешнему ключу. Разница заключается в том, что в Android SQLite примере мы получаем ссылку на выбранный объект Cursor из Spinner , а затем - значение столбца _ID Employer :
Что такое SQLite
SQLite - это система управления реляционными базами данных, похожая на Oracle , MySQL , PostgreSQL и SQL Server . Она реализует большую часть стандарта SQL , но в отличие от четырех упомянутых выше СУБД она не поддерживает модель « клиент-сервер ». Скорее, она встроена в конечную программу. Это означает, что можно связать базу данных SQLite с приложением и получить доступ ко всем возможностям БД в своем приложении.
Данная СУБД совместима как с Android , так и с iOS , и каждое приложение может создавать и использовать базу данных SQLite . В Android контакты и медиа хранятся и ссылаются на БД SQLite . Она является наиболее используемой СУБД в мире и самым распространенным программным обеспечением . Чтобы узнать о базах данных SQLite как можно больше, посетите официальный сайт SQLite .
Отличие SQLite от MySQL и аналогичных СУБД
Классические СУБД, такие как MySQL (а так же MS SQL, Oracle, PostgreeSQL) состоят из отдельного сервера, поддерживающего работу базы данных и прослушивающих определённый порт, на предмет обращения клиентов. В качестве клиента может выступать в том числе и расширение PHP, реализующего интерфейс, с помощью которого осуществляются запросы к базе. Движок SQLite и интерфейс к ней реализованы в одной библиотеке, что увеличивает скорость выполнения запросов. Такой сервер часто называют встроенным.
Встроенный сервер имеется и у других баз данных, например, у MySQL, но его использование требует лицензионных отчислений, поэтому не получило широкое распространение в мире открытых исходных кодов.
SQLite является бестиповой базой данных. Точнее, есть только два типа – целочисленный "integer" и текстовый "text". Причём "integer" используется преимущественно для первичного ключа таблицы, а для остальных данных пойдёт "text". Длина строки, записываемой в текстовое поле, может быть любой.
Класс SQLiteOpenHelper: Создание базы данных
Библиотека Android содержит абстрактный класс SQLiteOpenHelper, с помощью которого можно создавать, открывать и обновлять базы данных. Это основной класс, с которым вам придётся работать в своих проектах. При реализации этого вспомогательного класса от вас скрывается логика, на основе которой принимается решение о создании или обновлении базы данных перед ее открытием. Класс SQLiteOpenHelper содержит два обязательных абстрактных метода:
- onCreate() — вызывается при первом создании базы данных
- onUpgrade() — вызывается при модификации базы данных
Также используются другие методы класса:
- onDowngrade(SQLiteDatabase, int, int)
- onOpen(SQLiteDatabase)
- getReadableDatabase()
- getWritableDatabase()
В приложении необходимо создать собственный класс, наследуемый от SQLiteOpenHelper. В этом классе необходимо реализовать указанные обязательные методы, описав в них логику создания и модификации вашей базы.
В этом же классе принято объявлять открытые строковые константы для названия таблиц и полей создаваемой базы данных, которые клиенты могут использовать для определения столбцов при выполнении запросов к базе данных. Например, так можно объявить константы для таблицы CONTACT:
Лучше, если вы будете давать сразу понятные имена, указывающие на работу с таблицей. Если имя переменной TABLE_NAME ещё можно оставить, то для других лучше использовать более говорящие имена, например, KEY_NAME и KEY_PHONE или COLUMN_NAME, COLUMN_PHONE.
Ваш класс, расширяющий SQLiteOpenHelper, также неявно наследует интерфейс BaseColumns, в котором определена строковая константа _ID, представляющая имя поля для идентификаторов записей. В создаваемых таблицах базы данных поле _ID должно иметь тип INTEGER PRIMARY KEY AUTOINCREMENT. Описатель AUTOINCREMENT является необязательным. Часто в других примерах идентификатор создаётся вручную, смотрите как вам удобнее. Только всегда называйте его именно _id. Такое название используется в Android для работы с курсорами и поэтому придерживайтесь данного правила.
В методе onCreate() необходимо реализовать логику создания таблиц и при необходимости заполнить их начальными данными при помощи SQL-команды, например:
Здесь показана условная команда, в реальном коде вам нужно учитывать пробелы между константами, чтобы получилась правильная строка SQL-команды.
Также надо указать номер версии базы данных, начиная со значения 1. По этому номеру класс-обёртка будет понимать, что структуру базы данных следует обновить.
В методе onUpgrade() можно, например, реализовать запрос в базу данных на уничтожение таблицы (DROP TABLE), после чего вновь вызвать метод onCreate() для создания версии таблицы с обновленной структурой, например, так:
В параметрах метода используются номера версий базы данных - старая и новая. О номере версии говорилось выше.
Обновляется структура базы данных следующим образом. Сначала меняем порядковый номер.
При первой установке приложения базы данных ещё не существует. Тут проверять пока нечего. При установке новой версии приложения система проверит номер версии базы данных. Если он больше, чем было, то вызовется метод onUpgrade(). Если наоборот, то вызовется метод onDowngrade() (обычно так происходит редко).
Как использовать? Просто ставим условие на проверку.
Допустим, в таблицу нужно добавить новую колонку в дополнение к существующим колонкам NAME, DESCRIPTION и IMAGE_RESOURCE_ID. Для изменения таблицы используется выражение SQL с ключевым словом ALTER
Для замены имени таблицы используется выражение (меняем имя таблицы DOG на CAT):
Для удаления таблицы:
Соответственно, нужно вызвать метод SQLiteDatabase.execSQL(), передав ему нужную команду SQL.
Для удобства создадим вспомогательный метод updateDatabase().
Созданный метод теперь можно использовать в коде следующим образом.
Чтобы использовать реализацию вспомогательного класса, создайте новый экземпляр, передайте его конструктору контекст, имя базы данных, текущую версию и объект класса CursorFactory (если вы его используете). Вызовите метод getReadableDatabase() или getWritableDatabase(), чтобы открыть и вернуть экземпляр базы данных, с которой мы имеем дело (он будет доступен как для чтения, так и для записи). Вызов метода getWritableDatabase() может завершиться неудачно из-за проблем с полномочиями или нехваткой места на диске, поэтому лучше предусмотреть откат к методу getReadableDatabase().
Если база данных не существует, вспомогательный класс вызывает свой обработчик onCreate(); если версия базы данных изменилась, вызовется обработчик onUpgrade(). В любом случае вызов методов getWritableDatabase/getReadableDatabase, в зависимости от ситуации, вернет существующую, только что созданную или обновленную базу данных.
Оба метода имеют разные названия, но возвращают один и тот же объект. Только метод для чтения getReadableDatabase() сначала проверит доступность на чтение/запись. В случае ошибки метод проверит доступность на чтение и только потом уже вызовет исключение. Второй метод сразу проверяет доступ к чтению/записи и вызывает исключение при отказе в доступе.
Если вы планируете использовать несколько таблиц, то рекомендуется создавать для каждой таблицы отдельный класс.
Особенности SQLite
Все базы данных хранятся в файлах, по одному файлу на базу. Количество баз данных, а так же таблиц в них, ограниченно только свободным местом, имеющимся на сайте. А максимально возможный объём одной базы данных составляет 2 Тб.
Так как все данные хранятся в файлах, проблем с переносом базы данных с одного хостинга на другой не существует – достаточно лишь скопировать соответствующие файлы.
Метод openOrCreateDatabase: Открытие и создание баз данных без использования SQLiteOpenHelper
Вы можете открывать и создавать базы данных без помощи класса SQLiteOpenHelper, используя метод openOrCreateDatabase(), принадлежащий объекту Context вашего приложения. Получите доступ к базе данных в два шага. Сначала вызовите метод openOrCreateDatabase(), чтобы создать новую базу данных. Затем из полученного экземпляра базы данных вызовите execSQL(), чтобы выполнять команды на языке SQL, с помощью которых будут созданы таблицы и установлены отношения между ними.
Вставка данных. Общая информация
Теперь разберём подробнее, как делать вставки.
Подготовка
Чтобы включить привязку данных в приложении, нужно добавить в файл build.gradle следующий код:
Чтобы использовать как RecyclerView , так и CardView для отображения списков, нужно включить соответствующие библиотеки в разделе зависимостей в файле build.gradle :
Чтобы задействовать все возможности базы данных SQLite , лучше изучить синтаксис SQL .
Определение внешних ключей
На данный момент в нашем Android SQLite примере мы создали таблицу Employer , которую заполнили строками. Теперь создадим таблицу Employee , которая связана с таблицей Employer через столбец _ID Employer . Мы определяем класс Employee , который расширяет BaseColumns в классе SampleDBContract . Обратите внимание, что при создании таблицы Employee использовали " FOREIGN KEY(employer_id) REFERENCES employer(_id) ":
Интерфейс
Для начала создадим интерфейс программы. Для первой активности MainActivity выберем шаблон Basic Activity. Сразу же создадим вторую активность EditorActivity из шаблона Empty Activity.
В первой активности есть кнопка Floating Action Button, через которую будем попадать на вторую активность.
Вторая активность предназначена для добавления новых гостей, которые поселяются в наш отель "Кошкин дом". Настроим его.
Экран состоит из нескольких текстовых полей и одного выпадающего списка для выбора пола гостя.
Инициализируем текстовые поля и выпадающий список.
Добавим несколько строковых ресурсов.
Запускаем SQLite на эмуляторе
С помощью утилиты ADB можно запустить SQLite на эмуляторе и работать с базами данных напрямую.
Напомню, что можно активировать команду sqlitе3 для одной из перечисленных баз данных, введя следующую команду:
Для завершения работы с sqlite3 напишите:
Чтобы просмотреть список таблиц:
Быстрый доступ к главной таблице:
Таблица sqlite_master - это главная таблица (master table), в которой отслеживаются таблицы и виды, содержащиеся в базе данных. Следующая команда распечатывает инструкцию create для таблицы people, находящейся в базе данных contacts.db:
Это один из способов, позволяющих узнать названия всех столбцов, которые содержатся в таблице базы данных. Можно скопировать базу данных на локальный компьютер и изучать её в более комфортных условиях. Чтобы переместить файл contacts.db, можно дать следующую команду:
Создание таблицы
В SQL используется язык, очень похожий на разговорный английский. Так, для создания новой таблицы используется следующий синтаксис:
В переводе звучит так: СОЗДАТЬ ТАБЛИЦУ такую-то (первый_столбец тип столбца, второй_столбец тип столбца, . ).
Команды SQL принято писать заглавными буквами, хотя это не обязательно. Не путайте команды SQL с командами sqlite3.exe, которые начинаются с точки. Например, команду .help нужно вводить только в нижнем регистре.
В нашем случае для создания таблицы, которая будет содержать информацию о гостях, потребуется ввести команду.
CREATE TABLE guests(_id INTEGER, name TEXT, city TEXT, gender INTEGER, age INTEGER);
После ввода этой команды снова выполните команду .tables. Вы увидите созданную таблицу.
Теперь введите команду .schema , чтобы увидеть схему таблицы. Вы увидите собственную команду, которую вводили для создания таблицы.
Познакомимся ещё с одной командой PRAGMA TABLE_INFO(guests) . Видим некоторое подобие таблицы с нулевыми значениями.
Если вы где-то сделали ошибку и хотите заново создать таблицу, то для удаления таблицы используется команда DROP TABLE table_name;. При желании можно поставить проверочное условие IF EXISTS. Убедитесь, что таблицы больше нет командой .tables .
DROP TABLE IF EXISTS guests;
Небольшой совет - при вводе команд SQL принято записывать в столбик, отделяя параметры друг от друга. Когда вы находитесь в режиме ввода команд, то нажатие клавиши Enter приводит к переводу строки с приглашением вида . >. Продолжайте вводить команды в этом режиме. Когда вы закончите выражение точкой с запятой, то программа поймёт, что следующее нажатие Enter должно запустить команду. Для демонстрации я создал вторую таблицу guests2.
Небольшая подсказка: наши команды сохраняются в истории. Поэтому во время ввода вы можете нажать на клавишу "Стрелка Вверх" на клавиатуре, чтобы быстро получить доступ к длинной строке. Также можно нажать клавишу F7 - в этом случае появится диалоговое окно со списком предыдущих команд.
Экспорт данных
Можно экспортировать объекты базы данных в SQL-формате при помощи команды .dump. Без аргументов будет экспортирована вся база. Чтобы экспорт шел в файл, а не на экран (по умолчанию), то используйте команду .output [filename]. А чтобы восстановить вывод данных на экран, используйте команду .output stdout:
Когда вы выполните эти команды, то у вас на диске появится файл guests.sql (если такой файл уже был, то он будет перезаписан).
Через командную строку:
Дамп сохраняем в файле:
Для создания новой базы данных hotel.db из нашего дампа guests.sql можно так:
Другой способ создания базы данных заключается в использовании опции init:
В этом случае будет создана база, и мы войдем в оболочку программы. Можно добавить команду .exit, чтобы выйти из оболочки:
Импорт данных
Импортировать данные можно двумя способами. Если данные содержатся в SQL-формате, то можно воспользоваться командой .read. Если файл содержит данные в формате CSV, то используется команда .import [file][table]. Данные обычно разделяются вертикальной чертой |. Но можно использовать и другие разделители. Разделитель можно задать командой .separator, а увидеть используемый разделитель можно командой .show.
В строчке separator вы можете видеть используемый символ.
Мы использовали для экспорта команду .dump, поэтому, чтобы импортировать данные из созданного файла guests.sql, нам подойдет команда .read.
Экспорт и импорт части данных
Не всегда нужно сохранять всю базу, иногда нужно сохранить только её часть. Предположим, мы решили сохранить только те ряды таблицы, в которых имена котов заканчиваются на ik:
Теперь, если мы захотим импортировать сохраненные данные в такую же таблицу с схожей структурой, то делаем следующее:
Настройка
Мы можем поменять вид приглашения, который по умолчанию имеет вид sqlite> через команду .prompt. Давайте поменяем на более знакомое и правильное:
Теперь вместо глупого приглашения используется любимое нами слово.
Потренировавшись с созданием таблиц, перейдём к их наполнению. Существуют четыре базовых операции при работе с записями таблицы.
- Create - создать новую запись
- Read - прочитать запись
- Update - обновить запись
- Delete - удалить запись
По первым буквам операций создано сокращение CRUD для быстрого запоминания, что нужно реализовать программисту в своей программе.
Начнём с вставки новой записи в таблицу. Синтаксис команды.
Переводим: ВСТАВИТЬ В такую-то таблицу (первый_столбец, второй_столбец, . ) Значения (первое_значение, второе_значение, . )
Вставляем первую запись в таблицу.
INSERT INTO guests (_id, name, city, gender, age) VALUES (1, "Васька", "Питер", 1, 6);
Итак, в гостинице поселился первый гость. При вводе команды важно соблюдать очерёдность столбцов и их значений. Например, можно было указать имена столбцов в обратном порядке, но тогда и значения следовало бы ввести также в обратном порядке. Но обычно стараются перечислять столбцы в том же порядке, как они создавались.
Существует укороченная запись без перечисления столбцов. В этом случае нужно указывать все значения и в том порядке, в котором создавались соответствующие столбцы.
Проверить наличие записи можно с помощью команды:
SELECT * from guests;
Звёздочка (*) выводит все записи из указанной таблицы. Перед данной командой можно задать режим вывода записей через команду .mode режим. Доступны варианты: ascii, column, csv, html, insert, line, tabs, tcl.
Также удобно включить показ имён столбцов через команду .header on.
.header on .mode column SELECT * FROM guests;
Вы можете теперь вводить новые записи, не забывая увеличивать значение идентификатора _id. Но нет никакой гарантии, что однажды вы не ошибётесь и не введёте одинаковый идентификатор. Для таблицы базы данных это очень плохая ситуация, так как теряется принцип уникальности для записи.
Вторая возможная проблема - пропуск столбца. Например, возможна такая запись.
INSERT INTO guests (_id, city, gender, age) VALUES (1, "Питер", 1, 6);
Мы пропустили столбец name и после вставки записи там будет пустое значение. Получается, что гость живёт в номере отеля без имени. Непорядок.
Для решения подобных проблем в SQL есть специальные ключевые слова: PRIMARY KEY, AUTOINCREMENT, NOT NULL, DEFAULT value.
PRIMARY KEY (первичный ключ) обеспечивает уникальность в таблице. В таблице может быть только один первичный ключ.
Первичный ключ - столбец таблицы, имеющий уникальное значение для каждой записи. Назначается при создании таблицы. Ключ не может содержать NULL, потому что теряется уникальность, ведь в других записях тоже может оказаться NULL. Значения первичного ключа должны оставаться неизменными.
Во многих случаях для этой цели создают новый столбец, который будет содержать уникальный номер. В Android столбец называют _id.
Чтобы база данных сама заботилась об уникальности первичного ключа, можно добавить к нему ключевое слово AUTOINCREMENT, которое будет автоматически увеличивать значение на единицу при вставке новой записи.
AUTOINCREMENT (автоувеличение) автоматически вычисляет следующее значение ряда таблицы при добавлении. Удобно использовать у идентификаторов.
Поэтому скрипт создания таблицы должен иметь следующий вид.
Удалите таблицу guests с помощью команды DROP TABLE guest; и заново создайте таблицу с этим же именем.
Теперь для вставки новой записи вам не нужно указывать значение для первого столбца _id, база данных сама сгенерирует нужное значение. Вставим новые записи.
INSERT INTO guests (name, city, gender, age) VALUES ("Васька", "Питер", 1, 6); INSERT INTO guests (name, city, gender, age) VALUES ("Мурзик", "Мурманск", 1, 4);
DEFAULT value - если при вставке новой строки мы не зададим значения для столбца, то применится значение по умолчанию. Данный параметр можно комбинировать с предыдущим.
В этом случае мы можем пропустить столбец, но вместо ошибки база данных подставит значение по умолчанию.
Увы, но вам снова придётся удалить таблицу и воссоздать её по новому правилу.
Заново заселяем Ваську и Мурзика, команды не меняются. Допустим, к нам заехал необычный гость, у которого неудобно было спросить возраст и пол. Вводим только имя и город, остальное добавится автоматически по умолчанию.
INSERT INTO guests (name, city) VALUES ("Ктулху", "Москва");
Можно выводить не все записи из таблицы, а только нужные. Например, запись с идентификатором 1.
Если не нужны все столбцы, то перечисляем нужные через запятую вместо звёздочки.
Или такой вариант.
Чтобы не искать все записи, можно ограничить поиск условием WHERE, после которого идёт имя столбца и условие равенства. Показать всех котов, чей возраст меньше 15.
Вместо звёздочки можно указать столбцы, которые вам нужны. Например, нам нужны только имена котов с этим же условием.
Столбцы указываются через запятую. Нам нужны имена и адреса котов с этим же условием.
Условие WHERE можно объединять с помощью ключевого слова AND. Список котов младше 15 лет и проживающих в Москве.
Также доступны слова OR (ИЛИ):
Слов AND и OR может быть несколько в одном запросе.
Проверку на NULL можно сделать с помощью ключевого слова IS NULL (если столбец таблицы создавался без NOT NULL)
Ключевое слово LIKE позволяет сократить множество операторов OR. Например, мы хотим узнать имена котов, которые заканчиваются на "ик":
Символ % в строке указывает на любое слово с нужным окончанием (представляет любое количество неизвестных символов).
Также можно использовать спецсимвол _ для одного символа. Ищем Ваську.
Стоит заметить, что в командной строке примеры могут не работать, так как там не используется кодировка UTF-8. Проверяйте на английских словах. В других программах или в Android такой проблемы не будет, там всегда используется правильная кодировка.
С помощью ключевого слова BETWEEN можно быстро и удобно задать диапазон.
Сравните с более длинной записью
С помощью условия IN за которыми в скобках идут нужные значения, можно задать нужные параметры.
Ключевое слово NOT IN выполняет обратную задачу и позволяет получить записи, которые не входят в данное условие.
Ключевое слово NOT можно использовать не только с IN, но и с BETWEEN, LIKE.
Узнать число записей можно через функцию COUNT. Если запись содержит NULL, то она не учитывается.
Для показа минимального или максимального значения используются функции MIN или MAX:
Если нам нужно вывести только определённое количество записей, то используйте ключевое слово LIMIT с указанием значения.
Существует расширенная версия, когда можно указать два значения через запятую. В первой указывается номер записи (отсчёт от 0), а вторая - число записей. Например, показать вторую запись из таблицы.
Мы рассмотрели половину операций с записями - CREATE и READ. Теперь нужно научиться изменять данные. Конечно, самый простой способ - удалить запись, а затем добавить новую с исправленными данными. Но это очень неуклюжий способ.
Для этого существует команда UPDATE имя_таблицы SET column = value WHERE условие. После UPDATE указываете таблицу, после SET - в каком столбце нужно внести изменения и указывается новое значение, а затем указывается условие.
Можно обновлять группу столбцов, указывая их через запятую.
Команда UPDATE заменяет собой пару команд INSERT/DELETE. Обновить данные в нужном столбце:
Также можно производить математические действия: прибавлять, отнимать, умножать, делить. Увеличим возраст кота на день рождения.
Изменим прописку у Ктулху.
UPDATE guests SET city = "Нью-Йорк" WHERE name = "Ктулху";
Если не указать условие WHERE, то город изменится у всех гостей сразу. Удобно, если приехала большая делегация из одного города.
Последняя операция - удаление записи из таблицы. Команда DELETE FROM имя_таблицы;
Без условия WHERE мы удалим все записи. Вряд ли вам это нужно. Давайте выпишем из гостиницы Ктулху, вежливо объяснив ему, что отель только для котов. Выпроводив незванного гостя, удаляем запись из таблицы.
DELETE FROM guests WHERE _id = 3;
Вам не надо перечислять все столбцы, достаточно указать в условии нужный столбец. Условие WHERE работает аналогично как в команде SELECT и позволяет использовать ключевые слова LIKE, BETWEEN и т.д.
Кстати, вы можете посмотреть, какой идентификатор был вставлен в таблицу последним через команду:
Добавить новый столбец в таблицу можно с помощью необязательного ключевого слова ALTER, за которым идёт название столбца в таблице.
Чтобы указать, после какого столбца нужно добавить новый столбец, используйте ключевое слово AFTER.
Другие ключевые слова: FIRST, BEFORE, LAST, SECOND, THIRD.
Кроме ADD, также можно изменить имя и тип данных столбцов (CHANGE), изменить тип данных или позиции столбцов ( MODIFY ), удалить столбец из таблицы ( DROP ). Не все эти команды поддерживаются в SQLite, хотя часто используются в обычных SQL.
SQLite доступен на любом Android-устройстве, его не нужно устанавливать отдельно.
SQLite поддерживает типы TEXT (аналог String в Java), INTEGER (аналог long в Java) и REAL (аналог double в Java). Остальные типы следует конвертировать, прежде чем сохранять в базе данных. SQLite сама по себе не проверяет типы данных, поэтому вы можете записать целое число в колонку, предназначенную для строк, и наоборот.
Вы не найдёте здесь тип, работающий с датами. Можно использовать строковые значения, например, как 2013-03-28 (28 марта 2013 года). Для даты со временем рекомендуется использовать формат 2013-03-27T07:58. В таких случаях можно использовать некоторые функции SQLite для добавления дней, установки начала месяца и т.д. Учтите, что SQLite не поддерживает часовые пояса.
Также не поддерживается тип boolean. Используйте числа 0 для false и 1 для true.
Не используйте тип BLOB для хранения данных (картинки) в Android. Лучше хранить в базе путь к изображениям, а сами изображения хранить в файловой системе.
Обратите внимание, что здесь не используется популярный в MySQL тип varchar(n), ограничивающий длину строки.
Всё, что вам нужно для начала работы с базой данных - задать необходимые настройки для создания или обновления базы данных.
Так как сама база данных SQLite представляет собой файл, то по сути при работе с базой данных, вы взаимодействуете с файлом. Поэтому операции чтения и записи могут быть довольно медленными. Настоятельно рекомендуется использовать асинхронные операции, например, при помощи класса AsyncTask.
Когда ваше приложение создаёт базу данных, она сохраняется в каталоге DATA/data/имя_пакета/databases/имя_базы.db.
Метод Environment.getDataDirectory() возвращает путь к каталогу DATA.
Основными пакетами для работы с базой данных являются android.database и android.database.sqlite.
База данных SQLite доступна только приложению, которое создаёт её. Если вы хотите дать доступ к данным другим приложениям, вы можете использовать контент-провайдеры (ContentProvider).
Подписываем контракт
Теперь можно заняться интеграцией базы данных в приложение.
При работе с базой данных принято создавать новый пакет data внутри основного пакета. Щёлкаем правой кнопкой мыши по имени пакета, выбираем New | Package и вводим новое имя.
В последних рекомендациях Гугла рекомендуется создавать класс-контракт. Будем придерживаться этого правила. Мы как бы подписываем контракт на работу с базой данных и предоставляем все нужные данные.
Внутри созданного пакета создаём новый класс HotelContract. Класс-контракт является контейнером для базы данных и может содержать несколько внутренних классов, которые представляют отдельные таблицы (не забывайте, что база данных может содержать несколько таблиц). Внутри класса создаём внутренний класс. В нашем случае будет один класс для таблицы guests.
Нам следует задать схему таблицы и константы для столбцов для удобства. Класс будет выглядеть так.
В классе используется реализация интерфейса BaseColumn:
Что это нам даёт? В большинстве случаев работа с базой данных происходит через специальные объекты Cursor, которые требуют наличия в таблице колонки с именем _id. Вы можете создать столбец вручную в коде, а можно положиться на BaseColumn, который создаст столбец с нужным именем автоматически. Дело ваше. Если вы не будете работать с курсорами, то можете использовать и стандартное наименование id или вообще не использовать данный столбец, но не советую так поступать, чтобы не вырабатывать вредных привычек.
После создания класса мы можем изменить код в EditorActivity в том месте, где происходит выбор пола гостя через выпадающий список.
Курсоры
В Android запросы к базе данных возвращают объекты класса Cursor. Вместо того чтобы извлекать данные и возвращать копию значений, курсоры ссылаются на результирующий набор исходных данных. Курсоры позволяют управлять текущей позицией (строкой) в результирующем наборе данных, возвращаемом при запросе.
SQLiteOpenHelper
Следующий шаг - создание класса в пакете data, который наследуется от специального класса SQLiteOpenHelper и непосредственно работает с базой данных. В классе создаются константы для удобной работы. Также реализуются методы onCreate() и onUpgrade().
Созданный класс будет работать с базой данных - добавлять, выбирать, удалять записи и прочие операции.
Напомню, как выглядит схема нашей таблицы.
Щёлкаем правой кнопкой мыши на имени пакета в левой части студии и выбираем в меню New | Java Class и в диалоговом окне выбираем имя для нового класса, например, HotelDbHelper. Слово Helper обычно используют, чтобы показать, что класс является обёрткой (вспомогательным классом) какого-то абстрактного класса. Впрочем, вы можете придумать более замысловатое название, например, ILoveNewYork или CatsForever. Спустя год, когда вы вернётесь к своему примеру, это будет так увлекательно вспоминать, для чего был создан класс с таким красивым именем.
У нас появится заготовка. Наследуемся от SQLiteOpenHelper. Студия предложит создать два обязательных метода onCreate() и onUpgrade(), о которых поговорим позже.
После добавления методов студия по-прежнему ругается. Теперь ему подавай конструкторы. Получится такой код.:
Класс HotelDbHelper.
Третий параметр null в суперклассе используется для работы с курсорами. Сейчас их не используем, поэтому оставим в покое.
Как вы уже догадались, константа DATABASE_NAME отвечает за имя файла, в котором будет храниться база данных приложения. Можно придумать любое имя и обойтись без расширения. Но мне так привычнее.
Вторая константа DATABASE_VERSION требует дополнительных объяснений. Она отвечает за номер версии базы. Принцип её работы схож с номером версий самого приложения. Когда мы видим, что вышла новая версия Chrome 33, то понимаем, что пора обновляться. Аналогично поступает и само приложение, когда замечает, что номер версии базы стал другим. Как только программа заметила обновление номера базы, она запускает метод onUpgrade(), который у нас сформировался автоматически. В этом методе необходимо разместить код, который должен сработать при обновлении базы.
Метод onCreate() вопросов не вызывает - здесь создаётся сама база данных с необходимыми данными для работы.
Метод вызывается, если в устройстве нет базы данных и наш класс должен создать его. Как мы помним, у метода есть параметр db, который относится к классу SQLiteDatabase. У класса есть специальный метод execSQL(), которому нужно передать запрос (SQL-скрипт) для создания таблицы. Для создания таблицы в SQL используется команда CREATE TABLE . . Для удобства вынесем команду в отдельную строку. Аналогично поступим с командой DROP TABLE. Так как строка очень длинная и состоит из множества строковых переменных, которые нужно соединить в одну цепочку, то поступают следующим образом. Создаём ещё одну строковую константу для формирования скрипта и передадим её в метод.
Основная сложность - не пропустить пробелы в запросе. Очень часто пропущенный пробел становится источником проблем и ваше приложение не может создать таблицу. Можете сначала написать сам скрипт создания таблицы, а уже потом заменять отдельные слова константами. Идентификатор _id всегда должен использовать INTEGER PRIMARY KEY AUTOINCREMENT, остальные колонки на ваше усмотрение.
Теперь нужно объяснить, зачем нужен этот метод onUpgrade(). Представьте ситуацию, что вы первоначально создали в базе таблицу, в которую заносятся имена котов и их электронные адреса и телефоны (продвинутые кошаки). Вроде всё замечательно. Если нужно поздравить усатых-полосатых с Международным днём кошек, который отмечается 1 марта, то проблем нет никаких. У вас есть список имён, по которому вы можете пройтись и лично написать каждому письмо. Пользователи, скачавшие ваше приложение, с удовольствием заполняют базу данных и дружно пишут письма мелким почерком. И вдруг до вас дошло, что совершили непростительную ошибку. Вы забыли добавить в базу данных даты рождения котов. А значит их никто не поздравит и не погладит (((.
Вы исправляете досадное упущение и выкладываете новую версию программы в открытый доступ. Новые пользователи, которые установят программу первый раз, радуются жизни - у них есть все необходимые данные для работы. Но что делать тем, кто уже работает со старой программой? Обновившись, они увидят дополнительное текстовое поле для ввода даты рождения, но в старой базе нет колонки для хранения новых данных. И ваша программа завершится с ошибкой. Полностью удалять и устанавливать новую версию программы тоже не выход - тогда пропадут старые данные, что тоже не желательно. Для таких случаев вы пишете код в методе onUpgrade(), чтобы при обновлении поменялась структура базы данных у старых пользователей. Мы позже попробуем смоделировать эту ситуацию.
Итак, метод onUpgrade() вызывается при несовпадении версий. Часто в этом методе просто удаляют существующую таблицу и заменяют её на новую. Это самое простое и практичное решение. Впрочем, на первых порах, вам вряд ли придётся заниматься подобными делами, поэтому метод можно оставить даже пустым.
Когда ваше приложение будет готово, то в папке data/data/имя_пакета/databases появится файл hotel.db (позже я вам покажу). Этот файл и будет вашей базой данных, в которой будет находиться созданная вами таблица. На данный момент в студии нет готового плагина для просмотра таблиц (в Eclipse есть), но вроде уже видел плагин от сторонних разработчиков. А пока вам придётся скачивать из устройства файл базы данных и просматривать его на компьютере специальными программами, работающими с SQLite на локальном компьютере.
Вставка данных для проверки
Рассмотрим, как вставлять новые данные. Добавим в меню главной активности пункт "Вставить данные". Для вставки данных применяется метод ContentValues.put(). В методе указываются ключ и значение. В качестве ключа выступает имя столбца таблицы, а его значением будет нужная информация о госте. Так как идентификатор будет вставляться автоматически, то его не используем. После того, как вы заполните все столбцы таблицы, вызывайте метод insert(), который и разместит данные в базе.
Напишем вспомогательный метод.
Вызовем метод в обработчике нажатия пункта меню.
Сразу после вставки вызываем метод displayDatabaseInfo(), чтобы увидеть результат. Можно нажимать несколько раз. Так как данные жёстко заданы в коде, то увидим одинаковые данные, кроме увеличивающего значения идентификатора.
Читайте также: