〈kotlin〉Room③ データベースインスタンス
Android studioでkotlinを使ってAndroidアプリ作成の勉強中。
データベースSQLiteを簡単に扱うことができるRoomの実装をまとめる。
前回の記事の続き。
<kotlin> Room - ゆるプログラミング日記
「データベースのインスタンスは高コストで通常アプリに1つで良いためシングルトンにする」を解決したい。
データベースクラスの作成
RoomDatabaseを拡張する抽象クラスとDAOインスタンスを返す抽象メソッドを定義。
データベースが存在しない場合はデータベースを作成し、
一度作成した後は既存のデータベースを返すメソッドをコンパニオンオブジェクトで定義する。
@Database(entities = [Item::class], version = 1, exportSchema = false) abstract class ItemRoomDatabase : RoomDatabase() { abstract fun itemDao(): ItemDao companion object { @Volatile private var INSTANCE: ItemRoomDatabase? = null fun getDatabase(context: Context): ItemRoomDatabase { return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( context.applicationContext, ItemRoomDatabase::class.java, "item_database" ) .fallbackToDestructiveMigration() .build() INSTANCE = instance return instance } } } }
- exportSchema
データベースのスキーマをフォルダーにエクスポートするかどうか。
trueの場合エクスポートが行われ、スキーマのバージョン履歴を残せる。
デフォルトではtrueで、履歴を残さないデータベースはfalseを設定する。
- @Volatile
アノテーションをつけた変数はキャッシュに保存されなくなり、
書き込み読み込みが全てメインメモリとの間で行われる。
これにより値が常に最新になり、全ての実行スレッドで同じになる。
- INSTANCE変数
データベース作成時に、データベースに対する参照を保持する。
- getDatabase()メソッド
INSTANCE変数を返すか、
INSTANCE変数がnull(一度も作成されてない)の場合は初期化処理を行い、
作成したデータベースを返す。
- synchronized
このコードブロックには一度に 1 つのスレッドしか入ることができず、
データベースの初期化が一度しか行われないようにする。
(これがないと複数のスレッドが競合状態になってデータベース インスタンスを同時に要求した時、
結果的に 1 つではなく 2 つのデータベースが作成される可能性がある。)
- fallbackToDestructiveMigration()
スキーマが変更されたとき古いスキーマから新しいスキーマへの移行方法を定義した移行パスが必要になるが、
移行パスが見つからなかったらエラーが発生してしまう。
このオプションをつけると、
移行パスが見つからなければ古いデータは破棄してデータベースを再作成する。
データベースのインスタンス化
Applicationクラス内でインスタンスを作成する。
class MyApplication : Application(){ val database: ItemRoomDatabase by lazy { ItemRoomDatabase.getDatabase(this) } }
lazy デリゲートを使用して、アプリの起動時ではなく最初にアクセスされたときに
上記で作成したgetDatabase()が呼び出されてデータベースインスタンスが作成される。
Applicationクラスは、AndroidManifest.xmlのapplicationタグ内に、
「android:name=".MyApplication"」として含めておく必要がある。
データベースが必要なときはこのクラス内から取得する。
参考
Room を使用してデータを永続化する | Android Developers
Room データベースを移行する | Android デベロッパー | Android Developers
Database | Android Developers