Підключення до бази даних SQLite

В Android є вбудована підтримка однієї з поширених систем керування базами даних - SQLite. Для цього в пакеті android.database.sqlite визначено набір класів, які дозволяють працювати з базами даних SQLite. І кожен додаток може створити свою базу даних.

Щоб використовувати SQLite в Android, потрібно створити базу даних за допомогою виразу на мові SQL. Після цього база даних буде зберігатися в каталозі додатка за шляхом:

DATA/data/[Назва_додатка]/databases/[Назва_файла_бази_даних]

ОС Android за замовчуванням вже містить ряд вбудованих баз даних SQLite, які використовуються стандартними програмами - для списку контактів, для зберігання фотографій з камери, музичних альбомів тощо.

Основну функціональність по роботі з базами даних надає пакет android.database. Функціональність безпосередньо для роботи з SQLite знаходиться в пакеті android.database.sqlite.

База даних в SQLite представлена класом android.database.sqlite.SQLiteDatabase. Він дозволяє виконувати запити до бази даних, виконувати з нею різні маніпуляції.

Клас android.database.sqlite.SQLiteCursor надає запит і дозволяє повертати набір рядків, які відповідають цьому запиту.

Клас android.database.sqlite.SQLiteQueryBuilder дозволяє створювати SQL-запити.

Самі SQL-вирази представлені класом android.database.sqlite.SQLiteStatement, які дозволяють з допомогою плейсхолдерів вставляти в вирази динамічні дані.

Клас android.database.sqlite.SQLiteOpenHelper дозволяє створити базу даних з усіма таблицями, якщо їх ще не існує.

В SQLite застосовується наступна система типів даних:

  • INTEGER: представляє ціле число, аналог типу int в Java
  • REAL: представляє число з плаваючою точкою, аналог float та double в Java
  • TEXT: представляє набір символів, аналог String та char в Java
  • BLOB: представляє масив бінарних даних, наприклад, зображення, аналог типу int в Java

Збережені дані повинні відповідати відповідним типам у Java.

Створення та відкриття бази даних

Для створення або відкриття нової бази даних з коду Activity в Android ми можемо викликати метод openOrCreateDatabase(). Цей метод може приймати три параметри:

  • назва для бази даних
  • числове значення, яке визначає режим роботи (як правило, у вигляді константи MODE_PRIVATE)
  • необов'язковий параметр у вигляді об'єкта SQLiteDatabase.CursorFactory, який представляє фабрику створення курсора для роботи з базою даних

Наприклад, створення бази даних app.db:

SQLiteDatabase db = getBaseContext().openOrCreateDatabase("app.db", MODE_PRIVATE, null);

Для виконання запиту до бази даних можна використовувати метод execSQL класу SQLiteDatabase. В цей метод передається SQL-вираз. Наприклад, створення в базі даних таблиці users:

SQLiteDatabase db = getBaseContext().openOrCreateDatabase("app.db", MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS users (name TEXT, age INTEGER)");

Якщо нам треба не просто виконати вираз, а й отримати з бази даних якісь дані, то використовується метод rawQuery(). Цей метод як параметр приймає SQL-вираз, а також набір значень для виразу SQL. Наприклад, отримання всіх об'єктів з бази даних:

SQLiteDatabase db = getBaseContext().openOrCreateDatabase("app.db", MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS users (name TEXT, age INTEGER)");
Cursor query = db.rawQuery("SELECT * FROM users;", null);
if(query.moveToFirst()){
     
    String name = query.getString(0);
    int age = query.getInt(1);
}

Метод db.rawQuery() повертає об'єкт Cursor, за допомогою якого ми можемо витягнути отримані дані.

Можлива ситуація, коли в базі даних не буде об'єктів, і для цього методом query.moveToFirst() намагаємося переміститися до першого об'єкта, отриманого з бази даних. Якщо цей метод поверне значення false, це означає, що запит не отримав жодних даних з бази даних.

Тепер для роботи з базою даних створимо найпростіший додаток. Для цього створимо новий проект.

У файлі activity_main.xml визначимо найпростіший графічний інтерфейс:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp" >
 
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click"
        android:onClick="onClick"
        app:layout_constraintBottom_toTopOf="@id/textView"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="22sp"
        app:layout_constraintTop_toBottomOf="@id/button"
        app:layout_constraintLeft_toLeftOf="parent"/>
 
</androidx.constraintlayout.widget.ConstraintLayout>

А в класі MainActivity визначимо взаємодію з базою даних:

package com.example.sqliteapp;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void onClick(View view){
        SQLiteDatabase db = getBaseContext().openOrCreateDatabase("app.db", MODE_PRIVATE, null);
        db.execSQL("CREATE TABLE IF NOT EXISTS users (name TEXT, age INTEGER, UNIQUE(name))");
        db.execSQL("INSERT OR IGNORE INTO users VALUES ('Tom Smith', 23), ('John Dow', 31);");
 
        Cursor query = db.rawQuery("SELECT * FROM users;", null);
        TextView textView = findViewById(R.id.textView);
        textView.setText("");
        while(query.moveToNext()){
            String name = query.getString(0);
            int age = query.getInt(1);
            textView.append("Name: " + name + " Age: " + age + "\n");
        }
        query.close();
        db.close();
    }
}

По натисканню на кнопку тут спочатку створюється в базі даних app.db нова таблиця users, а потім в неї додаються два об'єкти в базу даних за допомогою SQL-виразу INSERT.

Далі з допомогою виразу SELECT отримуємо всіх доданих користувачів з бази даних у вигляді курсора Cursor.

Викликом query.moveToNext() переміщаємося в циклі while послідовно по всіх об'єктах.

Для отримання даних з курсора застосовуються методи query.getString(0) та query.getInt(1). У дужках в методи передається номер стовпця, з якого ми отримуємо дані. Наприклад, вище ми додали спочатку ім'я користувача у вигляді рядка, а потім вік у вигляді числа. Тому нульовим стовпцем буде рядкове значення, яке отримуємо за допомогою методу getString(), а наступним - першим стовпцем буде числове значення, для якого застосовується метод getInt().

Після завершення роботи з курсором і базою даних ми закриваємо всі пов'язані об'єкти:

query.close();
db.close();

Якщо ми не закриємо курсор, то можемо зіткнутися з проблемою витоку пам'яті.

І якщо ми звернемося до додатка, то після натискання на кнопку в текстове поле буде виведено додані дані: