Android Jetpack Room的詳細教程

1. 簡介

自從Google推出了Room,咱們能夠優雅的使用sqlite數據庫。
固然用Room+Paging的組合,代碼寫起來飛起來 關於Room+Paging的使用方法請參考下面的教程。
Paging在Android中的應用: juejin.im/post/5e75db…java

在App的build.gradle的文件中添加Room庫的引用。android

def room_version = "2.2.5"
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
    implementation "androidx.room:room-rxjava2:$room_version"
    implementation "androidx.room:room-testing:$room_version"
    implementation "androidx.room:room-ktx:$room_version"
複製代碼

2. 建立Entity

首先咱們要建立一個data class做爲數據庫的Entity class。 而後使用下面介紹的註解添加關於數據庫的額外信息。git

@Entity

在想建立的entity上面添加@Entity的註解。github

@Entity(tableName = "users_table")
data class User(...)
複製代碼

還能夠根據需求在@Entity後面能夠添加不少參數。sql

  1. tableName, 能夠爲Table起名字。示例,tableName = "users_table"
  2. primaryKeys, 能夠爲Table指定主鍵。示例,primaryKeys = {"firstName", "lastName"}
  3. Index, 爲了加快數據的查詢速度嗎,能夠添加索引。示例,indices = {@Index("lastName")
  4. unique,在索引當中須要確保兩個列中的信息的惟一性時能夠添加。示例indices = {@Index(value = {"first_name", "last_name"},unique = true)}

@PrimaryKey

@PrimaryKey註解跟上面@Entity中的primaryKeys的做用是同樣的。 針對自動增長的主鍵,還能夠添加autoGenerate=true數據庫

@PrimaryKey(autoGenerate = true)
val id: Int? = null,
複製代碼

@ColumnInfo

爲entity中的屬性添加列表名字name="name"app

@ColumnInfo(name = "birthday")
val birthday: String
複製代碼

@Ignore

若是在entity中存在不想存入數據庫的屬性,能夠添加忽略的註解@Ignoreide

@Ignore
val nationality: String
複製代碼

@Embedded

若是在Entity類裏面若是有其餘的對象,可使用@Embedded進行嵌套。固然要被嵌套的對象也須要是被@Entity加上註解的Entity類。函數

@Embedded
val address: Address
複製代碼

3. 建立Dao

@Dao

Dao的全稱是Data Access Object,是數據訪問對象是一個面向對象的數據庫接口。在通常開發中須要單獨抽象出一個Dao。 在Room中須要建立interface,並添加@Dao註解。post

@Dao
interface UserDao {}
複製代碼

@Query

須要在實現查詢的方法上面添加@Query,並加上要查詢的SQL語句。

@Query("SELECT * FROM users_table where first_name = :firstName")
suspend fun getUserByFirstName(firstName:String): List<User>
複製代碼

若是方法中有傳入的參數須要在SQL查詢語句中使用,能夠用:parameter來綁定參數。

@Insert

要在數據庫中插入數據時須要加上@Insert的註解,可是不須要加上SQL語句。 須要把插入數據庫的對象做爲參數傳入到函數中。

@Insert
suspend fun insertUser(users: List<User>)
複製代碼

@Delete

要在數據庫中刪除數據時須要加上@Delete的註解,可是不須要加上SQL語句。
須要把刪除的對象做爲參數傳入到函數中。

@Delete
suspend fun deleteUser(users: List<User>)
複製代碼

@Update

要在數據庫中更新數據時須要加上@Update的註解,可是不須要加上SQL語句。 須要把更新的對象做爲參數傳入到函數中。

@Update
public void updateUsers(User... user);
複製代碼

@Transaction

可使用@Transaction的註解,添加SQLite的事務。

@Transaction
suspend fun deleteAllAndInsertUser(users: List<User>) {
    deleteUser(getAll())
    insertUser(users)
}
複製代碼

總體代碼

@Dao
interface UserDao {

    @Query("SELECT * FROM users_table")
    suspend fun getAll(): List<User>

    @Insert
    suspend fun insertUser(user: User)
    
    @Update
    public void updateUsers(User... user);

    @Delete
    suspend fun deleteUser(users: List<User>)

    @Transaction
    suspend fun deleteAllAndInsertUser(users: List<User>) {
        deleteUser(getAll())
        users.forEach { insertUser(it) }
    }
}
複製代碼

4. 建立RoomDatabase

示例代碼以下:

@Database(version = 1, entities = [User::class])  // 添加Database的註解,還須要添加版本信息和entities信息
@TypeConverters(Converter::class)  // 添加TypeConverter的註解
abstract class AppDatabase : RoomDatabase() {

    companion object {
        private const val DB_NAME = "user_database.db"

        private var INSTANCE: AppDatabase? = null
        private var lock = Any()

        fun getInstance(context: Context): AppDatabase {
            synchronized(lock) {
                if (INSTANCE == null) {
                    // 第一個參數是Context, 第二個參數是DB的class,第三個參數是DB名字
                    INSTANCE =
                        Room.databaseBuilder(context, AppDatabase::class.java, DB_NAME).build()
                }

                return INSTANCE!!
            }
        }

        fun destroyInstance() {
            INSTANCE = null
        }
    }

    abstract fun getUserDao(): UserDao
}
複製代碼

數據庫類須要繼承RoomDatabase,同時必須聲明的是抽象類。 還有須要注意的一點是,建立數據庫的實例對性能的同樣特別大,因此不能重複建立。針對這個問題廣泛的作法是把建立實例的方法設計成Singleton模式

@Database

須要給數據庫的類上面加上@Database的註解。同時還須要不上下列信息。

  1. version,指定數據庫的版本。
  2. entities,須要指定全部的entity類。
@Database(version = 1, entities = [User::class])
複製代碼

@TypeConverter

Room是支持字符串和整型等的基本數據類型,可是遇到其餘類型的數據類型時,咱們就須要用@TypeConverter來進行數據類型的轉換。好比User裏面的生日的屬性是Date時,就須要進行數據類型的轉換。

class Converter {
    @TypeConverter
    fun longToDate(timeStamp: Long?): Date? {
        if (timeStamp == null) return null
        return Date(timeStamp)
    }

    @TypeConverter
    fun dateToLong(date: Date?): Long? {
        if (date == null) return null
        return date.time
    }
}
複製代碼

5. 數據庫升級,Migration

當App已經發布之後遇到須要更新和改變數據庫結構時,就須要用到數據庫的數據遷移。Room爲咱們提供了數據庫升級的功能。

// 從版本1升級到版本2
    val MIGRATION_1_2 = object : Migration(1, 2) {
        override fun migrate(database: SupportSQLiteDatabase) {
            database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, `name` TEXT, " +
                    "PRIMARY KEY(`id`))")
        }
    }

    // 從版本2升級到版本3
    val MIGRATION_2_3 = object : Migration(2, 3) {
        override fun migrate(database: SupportSQLiteDatabase) {
            database.execSQL("ALTER TABLE Book ADD COLUMN pub_year INTEGER")
        }
    }

    // 添加版本升級到Room的builder中
    Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name")
            .addMigrations(MIGRATION_1_2, MIGRATION_2_3).build()
    
複製代碼

6. Github

Github: github.com/HyejeanMOON…

其餘教程:
Android的屬性動畫(Property Animation)詳細教程: juejin.im/post/5eb7a5…
Android ConstraintLayout的易懂教程: juejin.im/post/5ea50a…
在RecyclerView中能夠應對多個ViewType的庫--Groupie: juejin.im/post/5e9059…
Google的MergeAdapter的使用: juejin.im/post/5e903f…
Paging在Android中的應用: juejin.im/post/5e75db…
Android UI測試之Espresso: juejin.im/post/5e6caa…
Android WorkManager的使用: juejin.im/post/5e635e…

相關文章
相關標籤/搜索