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.


