Android Jetpack架構(gòu)組件-Room基本使用

一、簡(jiǎn)介

Room有三個(gè)主要的組件:Database、Dao、Entity

  • 數(shù)據(jù)庫(kù)(Database):你可以使用該組件創(chuàng)建數(shù)據(jù)庫(kù)的持有者。該注解定義了實(shí)體列表,該類(lèi)的內(nèi)容定義了數(shù)據(jù)庫(kù)中的DAO列表。這也是訪問(wèn)底層連接的主要入口點(diǎn)。注解類(lèi)應(yīng)該是抽象的并且擴(kuò)展自RoomDatabase。在運(yùn)行時(shí),你可以通過(guò)調(diào)用Room.databaseBuilder()(理解為常規(guī)數(shù)據(jù)庫(kù)的定義)或者Room.inMemoryDatabaseBuilder()(數(shù)據(jù)保存在內(nèi)存中,即程序關(guān)掉,數(shù)據(jù)丟失)獲取實(shí)例。

  • 實(shí)體(Entity):這個(gè)組件代表了持有數(shù)據(jù)庫(kù)表記錄的類(lèi)。對(duì)每種實(shí)體來(lái)說(shuō),創(chuàng)建了一個(gè)數(shù)據(jù)庫(kù)表來(lái)持有所有項(xiàng)。你必須通過(guò)Database中的entities數(shù)組來(lái)引用實(shí)體類(lèi)。實(shí)體的每個(gè)成員變量都被持久化在數(shù)據(jù)庫(kù)中,除非你注解其為@Ignore

  • 數(shù)據(jù)訪問(wèn)對(duì)象(DAO):這個(gè)組件代表了作為DAO的類(lèi)或者接口。DAO是Room的主要組件,負(fù)責(zé)定義訪問(wèn)數(shù)據(jù)庫(kù)的方法。被注解@Database的類(lèi)必須包含一個(gè)無(wú)參數(shù)的抽象方法并返回被@Dao注解的類(lèi)型。當(dāng)編譯時(shí)生成代碼時(shí),Room會(huì)創(chuàng)建該類(lèi)的實(shí)現(xiàn)。

Database、Dao、Entities 和 app 的關(guān)系圖如下所示:

截屏2020-03-3114.55.04.png

二、如何使用

我們以簡(jiǎn)單示例來(lái)具體實(shí)現(xiàn)如上核心類(lèi):

1.添加依賴

添加相關(guān)room依賴包Room版本說(shuō)明,讀者可根據(jù)如上鏈接,獲取最新版本及按需依賴即可

2.定義Database類(lèi)

/**
 * des:Database
 * author:onexzgj
 */
@Database(entities = [Cheese::class], version = 1)   //注釋1
abstract class CheeseDb : RoomDatabase() {

    abstract fun cheeseDao(): CheeseDao

    companion object {
        private var instance: CheeseDb? = null

        fun get(context: Context): CheeseDb {
            if (instance == null) {
                //注釋2
                instance = Room.databaseBuilder(context, CheeseDb::class.java, "onexzgj")
                //是否允許在主線程進(jìn)行查詢
                    .allowMainThreadQueries()
                    .addCallback(object : RoomDatabase.Callback() {
                        override fun onCreate(db: SupportSQLiteDatabase) {
                            super.onCreate(db)
                        }         
                    })
                    .build()
            }
            return instance!!
        }
}
  • 在注釋1處
    使用@Database注解,表示是數(shù)據(jù)庫(kù)的入口類(lèi),參數(shù)entities是數(shù)組類(lèi)型,需要將當(dāng)前APP中的所有涉及到的數(shù)據(jù)庫(kù)表類(lèi),都寫(xiě)入這個(gè)參數(shù),version參數(shù)表示當(dāng)前數(shù)據(jù)庫(kù)的版本,其實(shí)還有一個(gè)參數(shù)為 exportSchema =true,默認(rèn)為true,按照字面意思為導(dǎo)出數(shù)據(jù)庫(kù)概要,即每次操作數(shù)據(jù)庫(kù)的一個(gè)摘要信息,但是需要注意的事,如果手動(dòng)設(shè)置為true時(shí),需要在build.gradle中的指定導(dǎo)出文件的位置,如下所示:
  defaultConfig {
        ...
        javaCompileOptions{
            annotationProcessorOptions{
                arguments=["room.schemaLocation":"$projectDir/schemas".toString()]
            }
        }
    }

這個(gè)時(shí)候,等程序運(yùn)行之后,就會(huì)在根目錄生成schemas目錄,并且產(chǎn)生一個(gè)json文件,如下所示:


image.png
  • 在注釋2處
    可以根據(jù)項(xiàng)目需要選擇內(nèi)存數(shù)據(jù)庫(kù),且還有如下回調(diào)方法,如下所示:
        //創(chuàng)建一個(gè)內(nèi)存數(shù)據(jù)庫(kù)
        //但是這種數(shù)據(jù)庫(kù)的數(shù)據(jù)只存在于內(nèi)存中,也就是進(jìn)程被殺之后,數(shù)據(jù)隨之丟失
        Room.inMemoryDatabaseBuilder(...)
                //是否允許在主線程進(jìn)行查詢
                    .allowMainThreadQueries() 
                //數(shù)據(jù)庫(kù)創(chuàng)建和打開(kāi)后的回調(diào)
                .addCallback()
                //設(shè)置查詢的線程池,一般不需要設(shè)置
                .setQueryExecutor()
                .openHelperFactory()
                //room的日志模式
                .setJournalMode()
                //數(shù)據(jù)庫(kù)升級(jí)異常之后的回滾,默認(rèn)重新進(jìn)行創(chuàng)建
                .fallbackToDestructiveMigration()
                //數(shù)據(jù)庫(kù)升級(jí)異常后根據(jù)指定版本進(jìn)行回滾
                .fallbackToDestructiveMigrationFrom()
                // 數(shù)據(jù)庫(kù)遷移升級(jí)時(shí)使用,后文會(huì)提到
                 .addMigrations(CacheDatabase.sMigration)

3.定義Dao

@Dao
interface CheeseDao {

    @Query("select * from cheese order by name ")
    fun findAllCheese(): DataSource.Factory<Int, Cheese>    //注釋1

    @Query("select * from cheese order by name ")
    fun getAllCheese(): List<Cheese>?      //注釋2

    @Insert
    fun insert(cheeses: List<Cheese>)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insert(cheese: Cheese)

    @Delete
    fun delete(cheese: Cheese)
}
  • 注釋1處
    返回的數(shù)據(jù)類(lèi)型為DataSource.Factory<Int,Cheese>,注釋2處返回的數(shù)據(jù)類(lèi)型為L(zhǎng)ist<Cheese> 從這里可以看到Room數(shù)據(jù)庫(kù)是原生支持Paging框架,如果不了解Paging的可以查看筆者之前的文章Paging框架

  • 注釋2處
    返回的數(shù)據(jù)類(lèi)型為 List<Cheese>? ,則可以直接返回List集合
    當(dāng)然這里也可以搭配Rxjava2使用,返回對(duì)象為 Flowable<List<CheeseAndUser>> ,后續(xù)再介紹

4、定義Entity

@Entity
data class Cheese(
    @PrimaryKey(autoGenerate = true) val id: Int, val name: String
)

通過(guò)@Entity注解標(biāo)注的類(lèi),則表示這個(gè)類(lèi)會(huì)映射到數(shù)據(jù)庫(kù)中,默認(rèn)表名為類(lèi)名,
通過(guò)@ PrimaryKey,標(biāo)明主鍵,通過(guò)設(shè)置autoGenerate參數(shù)設(shè)置true,則表示主鍵會(huì)自增長(zhǎng)

5、代碼中使用

        val allCheese = CheeseDb.get(this).cheeseDao().getAllCheese()
        Log.d("DATATA", allCheese?.get(0)?.name + ":" + allCheese?.size)

運(yùn)行結(jié)果如下所示:


運(yùn)行結(jié)果.png

到這里相信對(duì)Room數(shù)據(jù)庫(kù)有一個(gè)基本的了解,如果了解Orm或者GreenDao的同學(xué),應(yīng)該對(duì)上面的步驟或者創(chuàng)建不難理解,接下來(lái)介紹核心類(lèi)的具體參數(shù)的含義及用法

三、核心類(lèi)屬性講解

3.1 、@Entity注解包含的屬性有:

tableName:設(shè)置表名字,默認(rèn)是類(lèi)的名字。
indices:設(shè)置索引,按需添加,會(huì)提高查詢速度,增加更新和新增的操作時(shí)間
inheritSuperIndices:父類(lèi)的索引是否會(huì)自動(dòng)被當(dāng)前類(lèi)繼承,沒(méi)用到過(guò),暫不解釋
primaryKeys:設(shè)置主鍵,一般通過(guò)直接在主鍵字段上添加@PrimaryKey
foreignKeys:設(shè)置外鍵。
Ignore:設(shè)置不需要映射到數(shù)據(jù)庫(kù)中的字段可以使用,則不會(huì)在表中出現(xiàn)該字段

如下所示:

@Entity(tableName = "table_cheese")
data class Cheese(
    @PrimaryKey(autoGenerate = true) val id: Int, 
    
    @ColumnInfo(name = "testName")
    val name: String,
    @Ignore
    val temp:String
)

3.2、@Query注解是

它是DAO類(lèi)中使用的主要注釋?zhuān)试S對(duì)數(shù)據(jù)庫(kù)執(zhí)行讀/寫(xiě)操作。@Query在編譯的時(shí)候會(huì)驗(yàn)證準(zhǔn)確性,所以如果查詢出現(xiàn)問(wèn)題在編譯的時(shí)候就會(huì)報(bào)錯(cuò),如字段拼寫(xiě)常規(guī)錯(cuò)誤等。

Room還會(huì)驗(yàn)證查詢的返回值,如果返回對(duì)象中的字段名稱(chēng)與查詢響應(yīng)中的相應(yīng)列名稱(chēng)不匹配的時(shí)候,Room會(huì)通過(guò)以下兩種方式之一提醒您:
如果只有一些字段名稱(chēng)匹配,它會(huì)發(fā)出警告。
如果沒(méi)有字段名稱(chēng)匹配,它會(huì)發(fā)生錯(cuò)誤。

@Query注解value參數(shù):查詢語(yǔ)句,根據(jù)需求,完成查詢sql語(yǔ)句即可。

 @Query("select * from cheese  where name ==:name ")
 fun getCheese(name:String): List<Cheese>?

四、結(jié)語(yǔ)

到這里,Room的基本使用就差不多介紹完成了,那么在實(shí)際開(kāi)發(fā)中,僅僅掌握基本使用,是遠(yuǎn)遠(yuǎn)不夠的,如多表查詢,一對(duì)一、一對(duì)多等關(guān)系的查詢?nèi)绾螌?shí)現(xiàn)?配合Rxjava/LiveData/Paging的使用

本文示例代碼已上傳至Jetpack_Component

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容