Room
是 Google 在 2017 年所提供的組件,專門用來儲存本地端資料,建立 Database,比起原生的 SQLite,需要寫一大堆 SQL 語法,極容易出錯且語法繁瑣,Room
提供了更快速、簡潔的 Database 操作,關鍵的 CRUD 都可以用註解的方式來撰寫,大幅提升了建立本地資料庫的效率。
build.gradle 添加依賴
dependencies {
//Room
implementation "android.arch.persistence.room:runtime:2.1.0"
annotationProcessor "android.arch.persistence.room:compiler:2.1.0"
testImplementation "android.arch.persistence.room:testing:2.1.0"
Room
由三個部分組成 : Entity、DAO 和 Database
@Entity(tableName = TABLE_NAME)
class RoomEntity {
companion object {
const val TABLE_NAME = "room_entity"
}
@PrimaryKey(autoGenerate = true)
var id: Int = 0
var name: String = ""
@NonNull
@ColumnInfo(name = "timestamp", typeAffinity = ColumnInfo.TEXT)
var time = ""
@Ignore
var ignoreText = ""
}
class 上面以 @Entity(tableName = TABLE_NAME)
標示用來存取的物件
這裡面至少要有一個變數當作 PrimaryKey 用來當作每一個 Entity 物件的唯一識別,
並可透過 autoGenerate
來決定是否自動生成 id。
其中每個欄位名稱默認為變數的命名,如果需要自定義,
需加上註解 @ColumnInfo(name = "timestamp", typeAffinity = ColumnInfo.TEXT)
定義這個欄位的名稱和型別。
如果有不想要存入的變數,加上 @Ignore
註解即可
@Dao
interface RoomDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(item: RoomEntity): Long
@Insert
fun insertAll(item: RoomEntity)
@Query("SELECT * FROM room_entity WHERE name LIKE :name")
fun findByName(name: String): RoomEntity
@Query("SELECT * FROM room_entity")
fun getAll(): List<RoomEntity>
@Delete
fun delete(item: RoomEntity)
@Update
fun update(item: RoomEntity)
}
interface 上面以 @Dao
標示用來對資料庫操作的介面
CRUD 增刪查改都是透過這個介面來完成。
@Insert(onConflict = OnConflictStrategy.REPLACE)
表示新增物件時和舊物件發生衝突後的處置,
裡面有五個模式可以用,這邊我只簡單做測試這五個模式發生衝突時會發生什麼事,需要深入研究的可以看這邊
(默認)
需要尋找特定欄位符合名稱的就把參數傳進來再用 WHERE "欄位名稱" LIKE :參數名稱
查詢
@Query("SELECT * FROM room_entity WHERE name LIKE :name")
fun findByName(name: String): RoomEntity
@Database(entities = [(RoomEntity::class)], version = 1)
abstract class RoomDbHelper : RoomDatabase() {
companion object {
@Volatile private var instance: RoomDbHelper? = null
private val LOCK = Any()
operator fun invoke(context: Context)= instance ?: synchronized(LOCK){
instance ?: buildDatabase(context).also { instance = it}
}
private fun buildDatabase(context: Context) = Room.databaseBuilder(context,
RoomDbHelper::class.java, "item-list.db").build()
}
abstract fun getRoomDao(): RoomDao
}
註解為 @Database
的類別必須繼承 RoomDatabase
,並加上需要儲存的 Entity 類別 和 Version,
這裡用的是 Singleton
寫法,也是官方所推薦的,因為實體的產生很耗資源,而且也不需要多個資料庫實體,所以宣告為 Singleton
即可。
最後來看看如何使用吧
前面建立完三個主要物件後,其他地方的 CRUD 就簡單得多
val db = RoomDbHelper(this)
先把 RoomDbHelper 建立好,這個 this 傳入一個 Context。Room
不允許在主線程做操作,有一個辦法是在 Builder 那邊加入 allowMainThreadQueries()
不過 Kotlin 可以用更優雅的 協程 來完成這件事
Insert
存入一個 id = 3, name = "Wade" 的物件
GlobalScope.launch {
val user = db.getRoomDao().insert(RoomEntity().apply {
id = 3
name = "Wade"
})
}
Delete
先把要刪掉的那一筆 Query 出來,再直接刪掉就可以了。
GlobalScope.launch {
val user = db.getRoomDao().findByName("Wade")
db.getRoomDao().delete(user)
}
其他方法大同小異,就不列出來了
有任何問題或講得不清楚的地方歡迎留言和我討論。
更歡迎留言糾正我任何說錯的地方!
下一篇:Room (二) Query 的詳細用法以及如何升級資料庫版本