Room の使い方

概要

Android Kotlin Fundamentals 06.1 (Room) の備忘録です。ポイントとなるコードのみを抜粋しています。

目次

確認環境

  • AndroidStudio 3.5
    • compileSdkVersion 28
    • minSdkVersion 19
  • Gradle 5.4.1
  • Kotlin 1.3.11

参考情報

解説

build.gradle

buildscript {

    ext {
        kotlin_version = '1.3.11'
        archLifecycleVersion = '1.1.1'
        room_version = '2.0.0'
        coroutine_version = '1.0.0'
        gradleVersion = '3.3.0'
        navigationVersion = '1.0.0-alpha08'
        dataBindingCompilerVersion = gradleVersion // Always need to be the same.
    }

    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath "com.android.tools.build:gradle:$gradleVersion"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
    }
}

...

app/build.gradle

...

dependencies {
    ...
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
}

SleepNight.kt

...

@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
        @PrimaryKey(autoGenerate = true)
        var nightId: Long = 0L,

        @ColumnInfo(name = "start_time_milli")
        val startTimeMilli: Long = System.currentTimeMillis(),

        @ColumnInfo(name = "end_time_milli")
        var endTimeMilli: Long = startTimeMilli,

        @ColumnInfo(name = "quality_rating")
        var sleepQuality: Int = -1
)

SleepDatabaseDao.kt

...

@Dao
interface SleepDatabaseDao {
    @Insert
    fun insert(night: SleepNight)

    @Update
    fun update(night: SleepNight)

    @Query("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
    fun get(key: Long): SleepNight?

    @Query("DELETE FROM daily_sleep_quality_table")
    fun clear()

    @Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
    fun getTonight(): SleepNight?

    @Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
    fun getAllNights(): LiveData<List<SleepNight>>
}
  • アノテーションは Insert, Update, Delete, Query の 4 つ
  • LiveData を戻り値にするとデータベースのデータが変更された場合に変更を通知する
    • (変更の検知はデータベース単位?テーブル単位?便利だけどパフォーマンスは問題にならない?)

SleepDatabase.kt

...

@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {

    abstract val sleepDatabaseDao: SleepDatabaseDao

    companion object {
        @Volatile
        private var INSTANCE: SleepDatabase? = null

        fun getInstance(context: Context): SleepDatabase {
            synchronized(this) {
                var instance = INSTANCE
                if (instance == null) {
                    instance = Room.databaseBuilder(context.applicationContext, SleepDatabase::class.java, "sleep_history_database")
                            .fallbackToDestructiveMigration()
                            .build()
                    INSTANCE = instance
                }
                return instance
            }
        }
    }
}

SleepDatabaseTest.kt

...

@RunWith(AndroidJUnit4::class)
class SleepDatabaseTest {

    private lateinit var sleepDao: SleepDatabaseDao
    private lateinit var db: SleepDatabase

    @Before
    fun createDb() {
        val context = InstrumentationRegistry.getInstrumentation().targetContext
        db = Room.inMemoryDatabaseBuilder(context, SleepDatabase::class.java)
                .allowMainThreadQueries()
                .build()
        sleepDao = db.sleepDatabaseDao
    }

    @After
    @Throws(IOException::class)
    fun closeDb() {
        db.close()
    }

    @Test
    @Throws(Exception::class)
    fun insertAndGetNight() {
        val night = SleepNight()
        sleepDao.insert(night)
        val tonight = sleepDao.getTonight()
        assertEquals(tonight?.sleepQuality, -1)
    }
}
  • inMemoryDatabaseBuilder を使うことでテスト毎にデータベースをクリアする
  • allowMainThreadQueries を実行することでデータベースへの問い合わせを MainThread で実行できる様にする
    • 通常は MainThread でデータベースに問い合わせるとエラーになる