Android - Работа с базой данных (часть 2)

ноя 8, 21:01

Продолжаем продолжать

Итак, в последний раз мы прошли такую себе мини-лекцию по базам. Сегодня время пришло заняться практикой.

Начнем с первого пункта:

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

В Андроиде я насчитал 3 способа создания базы данных. Начнем с самого неправильно, и закончим самым православным.

1 способ – использовать класс SQLiteDatabase. Для начала сделаем небольшой обзор этого класса, так как в будущем он нам ой как пригодится.

Иерархия:


java.lang.Object
	android.database.sqlite.SQLiteClosable
		android.database.sqlite.SQLiteDatabase

Предков всего ничего: стандартный явовский Object и интерфейс SQLiteClosable. Последний мы вряд ли мы когда-нибудь будем использовать — это всего лишь внутренний интерфейс, которой исходя из названия содержит в себе методы, необходимые для закрытие (удаления) SQLite классов. В данном случае его наследует наш SQLiteDatabase, который следовательно представляет из себя ресурс, который можно прикрыть, если что)

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

  • void execSQL(String sql) — выполнение sql-запроса, который не является выборкой (т.е. без select). Это всякие CREATE TABLE, INSERT, DELETE и так далее.
  • Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) — большой и важный метод с кучей параметров. Используем для выборки. Параметры сами за себя говорят. Подробнее обсудим позже
  • Cursor rawQuery(String sql, String[] selectionArgs) — сырой, обычный, дикий sql-запрос. Очень полезно иметь возможность обратиться к базе, используя всякие хитрые Join’ы и так далее.

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

  • insert() – возвращает id вставленной строки
  • update() – возвращает количество обновленных строк
  • replace() – не часто встречал такой метод в других API. Нужно поковыряться еще. Замена.
  • delete() – возвращает количество удаленных строк

Дальше пойдут методы, которые возвращают ответ «Да» или «Нет»:

  • isOpen() – true, если база была не закрыта
  • isReadOnly() – true, если база была открыта только для чтения

Методы для работы с транзакциями:

  • beginTransaction() – начало
  • endTransaction() – конец
  • inTransaction() – true, если открыта транзакция
  • setTransactionSuccessful() – только после вызова этого метода транзакция будет закомичена.

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

Как я и говорил, существует 3 способа это сделать. И одним из этим способов является метод openDatabase(). Вот его полное описание:


static SQLiteDatabase openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags)

где:

  • path — путь к файлу базы данных. Путь для любой базы данных имеет вид: «/data/data/<package_name>/databases. <package_name> – имя пакета, которое вы указывали при создании проекта. Что-то вроде com.google.android.maps. Ну, или com.example.mysmallapp
  • factory — хз, что такое. По умолчанию стоит null — пусть так и стоит, пока не будет трогать.
  • flags — флаги или константы, определенные внутри класса SQLiteDatabase. Их всего четыре: CREATE_IF_NECESSARY (создавать базу, если это нужно), OPEN_READONLY (открыть только для чтения), OPEN_READWRITE (читать и писать), NO_LOCALIZED_COLLATORS (открыть без поддержки локализации)

Т.е. для того, чтобы создать базу с нуля нам нужно вызвать метод openDatabase() примерно таким образом:


SQLiteDatabase mDatabase = SQLiteDatabase.openDatabase("/data/data/com.example.app/databases/my.db", null, SQLiteDatabase.CREATE_IF_NECESSARY);

Все. Таким образом, мы получили новую, чистую базу данных для дальнейшей работы. Так как флаг SQLiteDatabase.CREATE_IF_NECESSARY пишут в конце очень часто при открытии, разработчики Андроида решили предложить метод openOrCreateDatabase() для краткости:


SQLiteDatabase mDatabase = SQLiteDatabase.openOrCreateDatabase("/data/data/com.example.app/databases/my.db", null);

Так даже удобнее. Но это только первый способ.

2 способ — это метод openOrCreateDatabase() в классе Context. О классе Context особо поговорим потом. Сейчас остановимся но том, что он представляет объект для общения с ОС Андроида.

Если вам доступен объект типа Context, то очень рекомендуется использовать его метод openOrCreateDatabase(). Почему? Для начала разберем его поподробнее:


SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory)

где

  • name — имя базы данных, уникальное в рамках приложения
  • mode — константа, для указания режима (MODE_PRIVATE или 0 – по умолчанию, MODE_WORLD_READABLE для чтения, MODE_WORLD_WRITEABLE для записи)
  • factory — пока не трогаем, ставим null

Возвращает этот метод объект типа SQLiteDatabase.

Какие преимущества у такого способа? Оно одно — нам не нужно указывать полный путь к файлу базы данных. Достаточно только ее имени. Так как путь к приложению мы уже знаем исходя из данных, которые предоставляет Context.

Для полноты картины разберем еще несколько методов класса Context для работы с базами данных:

  • boolean deleteDatabase(String name) — удаляем базу по имени. True, если завершилось успешно.
  • File getDatabasePath(String name) — возвращает абсолютный путь по имени базы

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

3 способ — использовать SQLiteOpenHelper.

Как становится ясно из названия, SQLiteOpenHelper помогает нам открывать/создавать базы данных. Начнем с описания класса:

Иерархия:


java.lang.Object
	android.database.sqlite.SQLiteOpenHelper

Здесь все. Также все просто и с методами. Их всего 6. 2 из них — абстрактные, и их следует переопределять в потомках. Перечислим первые 4:

  • void close() – закрыть все открытые соединения
  • SQLiteDatabase getReadableDatabase() – возвращает базу для чтения
  • SQLiteDatabase getWritableDatabase() – база для чтения и записи
  • onOpen(SQLiteDatabase db) — вызывается после того, как база будет открыта

И 2 абстрактных метода:

  • onCreate(SQLiteDatabase db) — вызывается после того, как база создана в первый раз. Здесь мы создаем необходимые таблицы. И если нужно, заносим в них какие-либо начальные данные.
  • onUpgrade(SQLiteDatabase db) — вызывается, когда базе нужен апгрейд. Здесь мы удаляем таблицы, создаем новые, добавляем поля и так далее.

Ну, и конструктор:


SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

где

  • context — контекст приложения. Именно через его метод openOrCreateDatabase() и работает SQLiteOpenHelper
  • name — имя базы
  • factory — говорили уже
  • version — версия базы. Используется, когда схему базы данных нужно обновить.

Приведем пример наследования и использования SQLiteOpenHelper:


class DatabaseHelper extends SQLiteOpenHelper {
  private static final String DATABASE_NAME = "data";
  private static final String DATABASE_CREATE = "create table test_table (_id integer primary key autoincrement, some_test text not null);";
DatabaseHelper(Context context) {
  super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
  db.execSQL(DATABASE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  db.execSQL("DROP TABLE IF EXISTS notes");
  onCreate(db);
}
}

Здесь мы использовали паттерн Шаблон для инкапсуляции внутренних данных. Для использования базы теперь нужно лишь вызвать getReadableDatabase() или getWriteableDatabase() метод. Т.е.:


DatabaseHelper mDbHelper = new DatabaseHelper(mCtx);
SQLiteDatabase mDb = mDbHelper.getWritableDatabase();

И мы получим нашу любимую базу. Все очень просто и лаконично смотриться.

Конец второй части

На этом пока остановимся. Дальше разберем, как же все таки работать со всеми этими методами — insert(), update(), replace(), delete() и тому прочее. Постараюсь этому как-нибудь выделить время. Пока всем.

Комментарии

  1. Прикольно расписано, а то полез в туториалсы от http://developer.android.com, то как-то со старта – темный лес =))

    Gremlin · дек 3, 00:03 · #

  2. Спасибо. Сам писал в процессе изучения. К сожалению, в последнее время не удается вернуться к Андроиду из-за нехватки времени.

    iobit · дек 3, 14:46 · #

 
---