Lekce 2 - Databáze v Androidu - Třída SQLiteOpenHelper
V minulé lekci, Databáze v Androidu - Vytvoření ukázkového projektu, jsme vytvořili ukázkový projekt aplikace Notepad pro ukládání vlastních poznámek do databáze, která je umístěna v úložišti zařízení.
V dnešním Java tutoriálu začneme pracovat na Java kódu databáze pro ukládání poznámek našeho poznámkového bločku. Později budeme pokračovat s psaním metod, kterými budeme k datům databáze přistupovat.
Definice struktury databáze
Naši práci si rozdělíme do dvou částí, v rámci kterých budeme deklarovat dvě třídy:
DbHelper
: Třída definující strukturu databáze.DataSource
: Třída s metodami pro přístup k datům databáze.
Pro lepší přehlednost souborů v projektu budeme soubory třídit do různých složek. V našem jednoduchém projektu bychom se bez tohoto obešli, ale u složitějších projektů je to velice přínosné z hlediska přehlednosti struktury jednotlivých částí Java kódu.
Vytvoříme tedy složku database
, do které obě zmíněné
třídy umístíme. V okně se strukturou projektu klikneme
pravým tlačítkem myši na složku notepad
. V zobrazeném menu
přes položku New zvolíme možnost Package:
V zobrazeném dialogu, na konec připraveného textového řetězce,
doplníme název naší nové složky database
a
potvrdíme klávesou Enter:
Třída DbHelper
Třída DbHelper
bude definovat strukturu
databáze včetně tabulek. Tuto třídu vytvoříme ve struktuře
projektu kliknutím pravým tlačítkem myši na naší složku
database
. V zobrazeném menu, přes položku New, zvolíme
možnost Java Class:
V dalším dialogu, do prázdného políčka, napíšeme název naší nové
třídy DbHelper
. Dále zkontrolujeme, že je vybrána možnost
Class. Zadání potvrdíme stisknutím klávesy Enter:
Třídu odvodíme od třídy SQLiteOpenHelper
:
public class DbHelper extends SQLiteOpenHelper { }
Konstanty
V úvodu třídy DbHelper
deklarujeme tyto konstanty:
TABLE_NOTES
- název tabulkyCOLUMN_...
- názvy sloupců tabulkyDATABASE_NAME
- název databázeDATABASE_VERSION
- číselná hodnota verze databázeTABLE_NOTES_CREATE
- textový řetězec s SQL příkazem pro vytvoření konkrétní tabulky.
Konstanty jsme deklarovali takto:
public class DbHelper extends SQLiteOpenHelper { public static final String TABLE_NOTES = "table_notes"; public static final String COLUMN_ID = "id"; public static final String COLUMN_TITLE = "title"; public static final String COLUMN_CONTENT = "content"; public static final String COLUMN_DATE = "date"; public static final String COLUMN_PRIORITY = "priority"; public static final String COLUMN_IS_ACTIVE = "is_active"; private static final String DATABASE_NAME = "database_notes.db"; private static final int DATABASE_VERSION = 2; private static final String TABLE_NOTES_CREATE = "CREATE TABLE " + TABLE_NOTES + " ( " + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + COLUMN_TITLE + " VARCHAR (100), " + COLUMN_CONTENT + " VARCHAR (100), " + COLUMN_DATE + " BIGINT, " + COLUMN_PRIORITY + " TINYINT, " + COLUMN_IS_ACTIVE + " TINYINT " + ");"; }
Konstruktor
Jelikož jsme naši třídu odvodili ze třídy SQLiteOpenHelper
musíme deklarovat:
- buď jeden ze tří možných konstruktorů
- nebo vlastní konstruktor, který musí volat rodičovský konstruktor v jedné ze tří možných variant
Ve třídě DbHelper
deklarujeme proměnnou context
a přidáme konstruktor:
public class DbHelper extends SQLiteOpenHelper { ... public Context context; public DbHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); this.context = context; }
Podrobnosti nalezneme v dokumentaci.
Metody
Nejprve si napíšeme metody onCreate()
,
doesDatabaseExist()
a onUpgrade()
. Nakonec si jen
ukážeme metody onDowngrade()
a onOpen()
.
Metoda onCreate()
Nyní přepíšeme metodu onCreate()
z předka
SQLiteOpenHelper
. Metoda je volána při vytvoření
databáze a dochází zde i k vytvoření všech databázových
tabulek. V metodě voláme metodu execSQL()
,
přijímající v parametru konstantu TABLE_NOTES_CREATE
. Konstanta
TABLE_NOTES_CREATE
obsahuje textový řetězec s SQL příkazem pro
vytvoření databázové tabulky s názvem
table_notes
:
public class DbHelper extends SQLiteOpenHelper { ... @Override public void onCreate(SQLiteDatabase database) { database.execSQL(TABLE_NOTES_CREATE); } }
Metodu execSQL()
lze použít pro jeden příkaz
SQL, který NENÍ příkazem SELECT
, ani žádným jiným
příkazem SQL, který by vracel data.
Metoda doesDatabaseExist()
Dále napíšeme metodu doesDatabaseExist()
. V metodě si
uložíme databázový soubor, který jsme získali z metody
getDatabasePath()
volané na Context
z přijatého
parametru context
. Z metody ale vrátíme pouze hodnotu
true
, nebo false
, podle toho, zda databázový soubor
existuje:
public class DbHelper extends SQLiteOpenHelper { ... public static boolean doesDatabaseExist(Context context, String dbName) { File dbFile = context.getDatabasePath(dbName); return dbFile.exists(); } }
Metoda onUpgrade()
Nakonec přepíšeme metodu onUpgrade()
z předka
SQLiteOpenHelper
:
public class DbHelper extends SQLiteOpenHelper { ... @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + TABLE_NOTES); onCreate(db); } }
Metoda je volána při potřebě upgradovat databázi po změně její struktury a je také automaticky volána při přechodu databáze na vyšší verzi. Na vyšší verzi databáze přecházíme vždy, pokud jakkoliv změníme strukturu databáze - například přidáním sloupce databázové tabulky, změna datového typu sloupce atd.
U změny struktury databáze musíme zvýšit hodnotu naší
konstanty DATABASE_VERSION
. Po každé změně verze
databáze budou ztracena veškerá
data, která dosud byla v databázi uložena.
Metody onDowngrade()
a
onOpen()
Metody onDowngrade()
a onOpen()
implementovat
nebudeme. Jen si řekneme k čemu slouží:
onDowngrade()
- metoda je volána při potřebě přechodu verze databáze na nižší verzionOpen()
- metoda je volána po dokončení konfigurace připojení k databázi, anebo poté, co bylo vytvořeno, upgradováno nebo downgradováno databázové schéma
Více tabulek
Databáze našeho poznámkového bločku bude pracovat s jednou
tabulkou. Pokud bychom chtěli mít tabulek více, pouze si ukážeme
postup a níže uvedené kódy do naší třídy DbHelper
implementovat nebudeme.
Ve třídě DbHelper
bychom deklarovali další konstanty s SQL
příkazy pro vytvoření dalších tabulek. Těla
přepisovaných metod onCreate()
a onUpgrade()
bychom
doplnili o další řádky s použitím příslušných parametrů pro
jednotlivé tabulky.
Metoda onCreate()
by pak mohla například vypadat nějak
takto:
@Override public void onCreate(SQLiteDatabase database) { database.execSQL(TABLE_1_CREATE_STRING); database.execSQL(TABLE_2_CREATE_STRING); database.execSQL(TABLE_3_CREATE_STRING); }
Metoda onUpgrade()
by pak mohla například vypadat nějak
takto:
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + TABLE_1_NAME); db.execSQL("DROP TABLE IF EXISTS " + TABLE_2_NAME); db.execSQL("DROP TABLE IF EXISTS " + TABLE_3_NAME); onCreate(db); }
V případě většího počtu tabulek by bylo nutné deklarovat
proměnné s textovými řetězci s definicí sloupců každé vytvářené
tabulky podobně, jako máme definovanou konstantu
TABLE_NOTES_CREATE
.
V příští části, Databáze v Androidu - Metody pro práci s databází, vytvoříme potřebná rozhraní a třídu
DataSource
s komponenty pro přístup k datům naší
databáze.