Некоторое время назад уже была статья посвящённая работе с SQLite под Android.Но, в ней рассматривались вопросы работы с этой СУБД на языке программирования Delphi с использованием библиотеки FireMonkey.
Однако, несмотря на значительные успехи альтернативных технологий разработки, большинство Android приложений по-прежнему создаются на «родном» для этой платформы языке Java. Что, в силу ряда причин, неудивительно.
Поэтому, рассмотрим взаимодействие с SQLite для приложений на Java.
В качестве примера используем туже самую базу данных, что и в случае Delphi. Напомним, эта база данных состоит из одной таблицы – перечень видов животных. В таблице всего два поля: id и Title (название вида животного).
Важно, отметить, что в отличие от Delphi в Java нет столь удобных инструментов для работы с базами данных и все операции необходимо выполнять вручную с использованием громоздких низкоуровневых классов. Вследствие этого, особенно в случае привязки операций с базой данных к пользовательскому интерфейсу, крайне желательно воспользоваться паттерном «Репозитоий».
Создание класса-хэлпера отвечающего за доступ к базе данных
Для начала необходимо создать класс, который обеспечит соединение с базой данных. Этот класс является наследником SQLiteOpenHelper.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class TestDbHelper extends SQLiteOpenHelper { //Имя файла базы данных private static final String DATABASE_NAME = "test.db"; //Версия базы данных private static final int DATABASE_VERSION = 1; private Context context; private SQLiteDatabase db; public TestDbHelper(Context con) { super(con, DATABASE_NAME, null, DATABASE_VERSION); this.context = con; } @Override public void onCreate(SQLiteDatabase db) { //Создание таблицы и заполнение начальными данными db.execSQL("CREATE TABLE Animals (id INTEGER PRIMARY KEY AUTOINCREMENT, Title TEXT NOT NULL);"); db.execSQL("INSERT INTO Animals (Title) VALUES('Cat');"); db.execSQL("INSERT INTO Animals (Title) VALUES('Dog');"); db.execSQL("INSERT INTO Animals (Title) VALUES('Rabbit');"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } |
Конструктор класса принимает в качестве единственного параметра контекст приложения. В методе onCreate реализовано создание таблицы и заполнение исходными данными.
Создание класса-репозитория для базы данных
Класс репозиторий будет реализовывать следующий функционал:
- Выборка записей, как с отбором, так и без него;
- Добавление новых записей;
- Редактирование существующих записей;
- Удаление существующих записей.
Вначале нужно выполнить подключение к базе данных. Для этого служат методы getWritableDatabase и getReadableDatabase класса SQLiteOpenHelper. Оба метода возвращают объект класса SQLiteDatabase, который собственно и предоставляет доступ к базе данных.
В силу того, что предполагается не только выборка данных, но также их добавление, редактирование и удаление, воспользуемся методом getWritableDatabase, так как метод getReadableDatabase предоставляет доступ только для чтения.
Подключение к базе данных можно создать либо сразу в конструкторе, либо в конкретном методе перед выполнением операций.
Операции добавления, редактирования и удаления реализуются достаточно просто с помощью метода execSQL, который позволяет выполнить любой SQL запрос, который не возвращает данные.
С выборкой данных несколько сложнее.
Для того чтобы получить данные из таблицы необходимо с помощью метода query получить курсор (объект класса Cursor) и уже сиз него извлечь необходимые данные.
Полный код класса-репозитория приведён ниже.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public class TestDbRepository { private SQLiteDatabase db; public TestDbRepository(Context context) { //Подключение к базе данных db = new TestDbHelper(context).getWritableDatabase(); } public void Insert(String item) { //Добавление записи db.execSQL("INSERT INTO Animals (Title) VALUES('" + item + "');"); } public void Update(int id, String newTitle) { //Редактирование записи db.execSQL("UPDATE Animals SET Title='" + newTitle + "' where id=" + id); } public void Delete(int id) { //Удаление записи db.execSQL("DELETE FROM Animals WHERE id=" + id); } public ArrayList getData(String where) { //Вывод записей с отбором (where!=null) и без ArrayList list = new ArrayList(); Cursor cursor = db.query("animals", null, where, null, null, null, null); if ((cursor != null) && (cursor.getCount() > 0)) { cursor.moveToFirst(); do { list.add(cursor.getString(1)); } while (cursor.moveToNext()); } return list; } } |
Работа с классом-репозиторием из приложения
Рассмотрим пример работы созданного класса-репозитория в некотором приложении.
Перед работой с базой данных создаём его объект. В данном случае, при создании объекта класса-репозитория одновременно создаётся и подключение к базе данных.
1 2 3 |
private TestDbRepository tdr; … tdr= new TestDbRepository(getApplicationContext()); |
Для добавления, редактирования или удаления данных достаточно вызвать соответствующие методы класса-репозитория.
Добавление:
1 2 3 |
if ((tdr != null) && (titleField.getText().length() > 0)) { tdr.Insert(titleField.getText().toString()); } |
Редактирование данных (на примере записи с id=3):
1 2 3 |
if ((tdr != null) && (titleField.getText().length() > 0)) { tdr.Update(3, titleField.getText().toString()); } |
Удаление данных (на примере записи с id=4):
1 2 3 |
if (tdr != null) { tdr.Delete(4); } |
На скриншотах выше также показаны результаты выборки всех записей для того чтобы наглядно показать работу методов по манипуляции данными.
Сама выборка реализуется в приложении следующим образом:
1 2 3 |
if (tdr != null) { ArrayList asl = tdr.getData(null); for (int i = 0; i |
Если же необходимо осуществить выборку с отбором по некоторому условию, то достаточно просто передать методу getData класса-репозитория это условие в формате SQL (то есть, как оно должно записываться в предложении WHERE SQL запроса).
Например, выберем из базы данных запись с id=2.
1 2 3 |
if (tdr != null) { ArrayList asl = tdr.getData("id=2"); for (int i = 0; i |
Некоторые замечания относительно приведённого способа работы с SQLite
Реализация паттерна «Репозиторий» в виде отдельного класса создаёт дополнительную «прослойку» между инфраструктурой работающей непосредственно с базой данных и логикой самой программы.
При желании можно легко без этого обойтись, и есть немало примеров того, как это сделать. Но, такое «упрощение» может быть эффективно только в случае простых приложений работающих с базами данных.
В тоже время данный подход обеспечивает необходимое удобство и гибкость при разработке программ любой сложности, а также их сопровождении. Так как алгоритмы работы с базой данных и алгоритмы самой программы изолированы друг от друга, у разработчиков появляется возможность, как минимум:
- Изменять и то и другое почти независимо друг от друга;
- Применять простые в использовании методы класса-репозитория вместо сложных конструкций на основе классов Android SDK;
Именно поэтому настоятельно рекомендуется при работе с SQLite под Android на Java всё-таки использовать этот паттерн. Время и силы, потраченные на его реализацию если не сразу, то в процессе дальнейшего сопровождения и развития проекта обязательно себя оправдают.
Добавить комментарий