前言
Room 是官方推出的一個在 SQLite 上提供抽象層的持久儲存庫,提供了強大而可靠的 SQL 物件對映能力,並且支援 LiveData
和 RxJava
。
在專案中新增以下依賴
def room_version = "2.1.0-alpha04"
def lifecycle_version = "2.0.0"
def rxjava_version = '2.1.7'
def rxandroid_version = '2.1.0'
// Room
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-rxjava2:$room_version"
// RxJava
implementation "io.reactivex.rxjava2:rxjava:$rxjava_version"
implementation "io.reactivex.rxjava2:rxandroid:$rxandroid_version"
// ViewModel and LiveData
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation 'com.google.code.gson:gson:2.8.5'
// 檢視資料庫
implementation 'com.facebook.stetho:stetho-okhttp3:1.5.0'
複製程式碼
當非同步查詢資料的時候,返回的物件可以是一個 LiveData
或者 Flowable
。如:
@Query("SELECT * FROM user")
abstract fun getAllUsers(): Flowable<List<User>>
@Query("SELECT * FROM user")
abstract fun getAllUser(): LiveData<List<User>>
複製程式碼
當我們儲存的實體類中包含 List
,如果按照普通的方式去定義 Entity
。編譯的時候就會報以下錯誤:
Cannot figure out how to save this field into database. You can consider adding a type converter for it.
複製程式碼
這是因為 Room
無法直接儲存 List
型別的資料,接下來我們將解決這個問題。
實踐
-
假設一個
User
物件會有很多本喜歡的書籍,一般定義的Entity
類是以下格式:@Entity(tableName = "user") data class User( @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Int, @ColumnInfo(name = "name") val name: String, @ColumnInfo(name = "books") val books: List<Book> ) data class Book( val bookName: String ) 複製程式碼
-
目前的情況下,編譯專案就會遇到前面提到的錯誤。我們可以藉助
@TypeConverter
去轉換任意物件。例如定義一個BookConverters
class BookConverters { @TypeConverter fun stringToObject(value: String): List<Book> { val listType = object : TypeToken<List<Book>>() { }.type return Gson().fromJson(value, listType) } @TypeConverter fun objectToString(list: List<Book>): String { val gson = Gson() return gson.toJson(list) } } 複製程式碼
-
在實體類中新增 @TypeConverters 註解
@Entity(tableName = "user") @TypeConverters(BookConverters::class) data class User( @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Int, @ColumnInfo(name = "name") val name: String, @ColumnInfo(name = "books") val books: List<Book> ) data class Book( val bookName: String ) 複製程式碼
@TypeConverters
這個註解的作用,就是告訴 Room
可以使用哪些額外的型別轉換器。
一般定義的轉換器類格式都是固定的:
class AnyConverters {
@TypeConverter
fun stringToObject(value: String): List<Any> {
val listType = object : TypeToken<List<Any>>() {
}.type
return Gson().fromJson(value, listType)
}
@TypeConverter
fun objectToString(list: List<Any>): String {
val gson = Gson()
return gson.toJson(list)
}
}
複製程式碼
使用 Facebook
推出的 Stetho
可以很方便的檢視資料庫中內容: