0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

深入了解Room 2.4.0版本的新增功能

谷歌開發(fā)者 ? 來源:谷歌開發(fā)者 ? 作者:谷歌開發(fā)者 ? 2022-01-25 11:07 ? 次閱讀

在 Google I/O 2019,我們分享了 Room 2.2 的最新進(jìn)展。盡管當(dāng)時(shí)已經(jīng)支持了很多功能,如支持 Flow API,支持預(yù)填充數(shù)據(jù)庫,支持一對一及多對多數(shù)據(jù)庫關(guān)系,但是開發(fā)者們對 Room 有著更高的期望,我們也致力于此,在 2.2.0 - 2.4.0 版本中發(fā)布了很多開發(fā)者們期待的新功能!包括自動(dòng)化遷移,關(guān)系查詢方法以及支持 Kotlin Symbol Processing (KSP) 等等。下面我們就來逐一介紹這些新功能!

自動(dòng)化遷移

在談自動(dòng)化遷移之前,先看看什么是數(shù)據(jù)庫遷移。假如您更改了數(shù)據(jù)庫 schema,就需要根據(jù)數(shù)據(jù)庫版本進(jìn)行遷移,以防用戶設(shè)備內(nèi)置數(shù)據(jù)庫中現(xiàn)有數(shù)據(jù)丟失。

如果您使用 Room,那么在數(shù)據(jù)庫遷移過程中會進(jìn)行檢查并驗(yàn)證更新后的 schema,另外您也可以在 @Database 中設(shè)置 exportSchema,來導(dǎo)出 schema 信息

對于 Room 2.4.0 版本之前的數(shù)據(jù)庫遷移,您需要實(shí)現(xiàn) Migration 類,并在其中編寫大量復(fù)雜冗長的 SQL 語句,來處理不同版本之間的遷移。這種手動(dòng)遷移的形式,非常容易引發(fā)各種錯(cuò)誤。

現(xiàn)在 Room 支持了自動(dòng)遷移,讓我們通過兩個(gè)示例來對比手動(dòng)遷移和自動(dòng)遷移:

修改表名

假設(shè)有一個(gè)包含兩個(gè)表的數(shù)據(jù)庫,表名分別是 Artist 和 Track,現(xiàn)在想要將表名 Track 改為 Song。

如果使用手動(dòng)遷移,必須編寫和執(zhí)行 SQL 語句才能更改,需要如下操作:

val MIGRATION_1_2: Migration = Migration(1, 2) {    fun migrate(database: SupportSQLiteDatabase) {        database.execSQL("ALTER TABLE `Track` RENAME TO `Song`")    }}
如果使用自動(dòng)遷移,您只需要在定義數(shù)據(jù)庫時(shí)添加 @AutoMigration 配置,同時(shí)提供兩個(gè)版本數(shù)據(jù)庫導(dǎo)出的 schema。Auto Migration API 將為您生成并實(shí)現(xiàn) migrate 函數(shù),編寫并執(zhí)行遷移所需的 SQL 語句。代碼如下:
@Database(    version = MusicDatabase.LATEST_VERSION    entities = {Song.class, Artist.class}    autoMigrations = {        @AutoMigration (from = 1,to = 2)    }    exprotSchema = true)

修改字段名

現(xiàn)在,演示一個(gè)更復(fù)雜的場景,假設(shè)我們要將 Artist 表中的 singerName 字段修改為 artistName。

雖然這看起來很簡單,但是由于 SQLite 并沒有提供用于此操作的 API,因此我們需要根據(jù) ALERT TABLE 實(shí)現(xiàn),有如下幾步操作:

1.獲取需要執(zhí)行更改的表

2.創(chuàng)建一個(gè)新表,滿足更改后的表結(jié)構(gòu)

3.將舊表的數(shù)據(jù)插入到新表中

4.刪除舊表

5.把新表重命名為原表名稱

6.進(jìn)行外鍵檢查

遷移代碼如下:

val MIGRATION_1_2: Migration = Mirgation(1, 2) {    fun migrate(db: SupportSQLiteDatabase) {        db.execSQL("CREATE TABLE IF NOT EXISTS `_new_Artist`(`id` INTEGER NOT             NULL, artistName` TEXT, PRIMARY KEY(`id`)"        )        db.execSQL("INSERT INTO `_new_Artist` (id,artistName)             SELECT id, singerName FROM `Artist`"        )        db.execSQL("DROP TABLE `Artist`")        db.execSQL("ALTER TABLE `_new_Artist` RENAME TO `Artist`")        db.execSQL("PRAGMA foreign_key_check(`Artist`)")    }}

從上面的代碼就可以看出,如果使用手動(dòng)遷移,即使兩個(gè)版本之間僅有一處更改,也可能需要繁瑣的操作,并且這些操作極易出錯(cuò)。

那我們來看看自動(dòng)遷移該如何使用。在上面的示例中,自動(dòng)遷移無法直接處理重命名表中的某一列,因?yàn)?Room 在進(jìn)行自動(dòng)遷移時(shí),會遍歷兩個(gè)版本的數(shù)據(jù)庫 schema,通過比較來檢測兩者之間的更改。在處理列或者表的重命名時(shí),Room 無法明確發(fā)生了什么更改,此時(shí)可能有兩種情況,是刪除后新添加的?還是進(jìn)行了重命名?處理列或者表的刪除操作時(shí)也會有同樣問題。

所以我們需要給 Room 添加一些配置來說明這些不確定的場景——定義 AutoMigrationSpec。AutoMigrationSpec 是定義自動(dòng)遷移規(guī)范的接口,我們需要實(shí)現(xiàn)該類,并在實(shí)現(xiàn)類上添加和修改相對應(yīng)的注解。本例中,我們使用 @RenameColumn 注解,并在注解參數(shù)中,提供表名、列的原始名稱以及更新后的名稱。如果在遷移完成之后,還需要執(zhí)行其他任務(wù),可以在 AutoMigrationSpec 的 onPostMigrate 函數(shù)中進(jìn)行處理,相關(guān)代碼如下:

@RenameColumn(    tableName = "Artist",    fromColumnName = "singerName",    toColumnName = "artistName")static class MySpec : AutoMigrationSpec {    override fun onPostMigrate(db: SupportSQLiteDatabase) {        // 遷移工作完成后處理任務(wù)的回調(diào)    }}

完成 AutoMigrationSpec 的實(shí)現(xiàn)后,還需要將其添加到數(shù)據(jù)庫定義時(shí)配置的 @AutoMigation 中,同時(shí)提供兩個(gè)版本的數(shù)據(jù)庫 schema,Auto Migration API 將生成和實(shí)現(xiàn) migrate 函數(shù),配置代碼如下:

@Database(    version = MusicDatabase.LATEST_VERSION    entities = {Song.class, Artist.class}    autoMigrations = {        @AutoMigration (from = 1,to = 2,spec = MySpec.class)    }    exprotSchema = true)

上面的案例提到了 @RenameColumn,相關(guān)的變更處理注解有如下幾種:

  • @DeleteColumn
  • @DeleteTable
  • @RenameColumn
  • @RenameTable

假設(shè)在同一遷移中有多個(gè)更改需要配置,我們還可以通過這些可復(fù)用的注解簡化處理。

測試自動(dòng)遷移

假設(shè)您在一開始就使用了自動(dòng)遷移,現(xiàn)在希望測試其是否正常工作,可以使用現(xiàn)有的 MigrationTestHelper API 無需任何更改。如以下代碼:

@Testfun v1ToV2() {    val helper = MigrationTestHelper(        InstrumentationRegisty.getInstrumentation(),            AutoMigrationDbKotlin::class.java    )    val db: SupportSQLiteDatabase = helper.runMigrationsAndValidate(        name = TEST_DB,        version = 2,        validateDroppedTables = true    )}

在無需額外配置的情況下,MigrationTestHelper 將自動(dòng)運(yùn)行并驗(yàn)證所有自動(dòng)遷移。在 Room 內(nèi)部,如果存在自動(dòng)遷移,它們將自動(dòng)添加到需要運(yùn)行和驗(yàn)證的遷移列表中。

需要注意的是,開發(fā)者提供的遷移具有更高的優(yōu)先級,也就是說,如果您定義自動(dòng)遷移的兩個(gè)版本之間,已經(jīng)定義了手動(dòng)遷移,那么手動(dòng)遷移將優(yōu)先于自動(dòng)遷移。

關(guān)系查詢方法

關(guān)系查詢也是新增的一個(gè)重要功能,我們還是用一個(gè)示例說明。

假設(shè)我們使用與之前相同的數(shù)據(jù)庫和表,現(xiàn)在表名分別為 Artist 和 Song。如果我們希望獲得音樂人到歌曲的映射集合,就要在 artistName 和 songName 之間建立關(guān)系。如下圖中 Purple Lloyd 與其熱門歌曲《Another Tile in the Ceiling》和《The Great Pig in the Sky》匹配,AB/CD 將與其熱門歌曲《Back in White》和《Highway to Heaven》匹配。

使用 @Relation
如果使用 @Relation 和 @Embedded 反應(yīng)該映射關(guān)系,則有如下代碼:
data class ArtistAndSongs(    @Embedded    val artist: Artist,    @Relation(...)    val songs: List) @Query("SELECT * FROM Artist")fungetArtistsAndSongs():List

在此方案中,我們創(chuàng)建了全新的數(shù)據(jù)類,將音樂人和歌曲列表相關(guān)系。但是這種額外創(chuàng)建 data 類的方式,容易造成代碼繁冗的問題。而 @Relation 中并不支持過濾、排序、分組或組合鍵,其設(shè)計(jì)初衷也是用于數(shù)據(jù)庫中只有一些簡單的關(guān)系,雖然受限于關(guān)系結(jié)果,但這是一種快速完成較簡單任務(wù)的便捷方法。

所以為了支持復(fù)雜關(guān)系的處理,我們并沒有擴(kuò)展 @Relation,而是希望您充分發(fā)揮 SQL 的潛能,因?yàn)樗墓δ芊浅?qiáng)大。

接下來讓我們來看看 Room 如何利用全新的功能來解決這一問題。

使用全新關(guān)系查詢功能

為了表示前面所示的音樂人與其歌曲之間的關(guān)系,我們現(xiàn)在可以編寫一個(gè)簡單的 DAO 方法,其返回類型為 Map,而我們需要做的僅僅是提供 @Query 和返回標(biāo)記,Room 將為您處理其余的一切!相關(guān)代碼如下:

@Query("SELECT * FROM Artist JOIN Song ON Artist.artistName = Song.songArtistName")fungetAllArtistAndTheirSongsList():Map>,>

在 Room 內(nèi)部,實(shí)際上要做的是找到音樂人、歌曲和 Cursor 并將它們放入 Map 中的 Key 和 Value 中。

在本例中,涉及到一對多的映射關(guān)系,其中單個(gè)音樂人映射到一個(gè)歌曲集合。當(dāng)然我們也可以使用一對一映射,如下文所示:

// 一對一映射關(guān)系@Query("SELECT * FROM Song JOIN Artist ON Song.songArtistName = Artist.artistName")fungetSongAndArtist():Map,>

使用 @MapInfo

實(shí)際上,您可以通過 @MapInfo 在映射的使用中更加靈活。

MapInfo 是用于說明開發(fā)者配置的輔助程序 API,類似于前面談到的自動(dòng)遷移更改注解。您可以使用 MapInfo 明確說明您希望如何處理查詢到的 Cursor 所包含的信息。使用 MapInfo 注解您可以指定輸出的數(shù)據(jù)結(jié)構(gòu)中用于查詢的 Key 和 Value 所映射的列。需要注意,用于 Key 的類型必須實(shí)現(xiàn) equals 和 hashCode 函數(shù)因?yàn)檫@對映射過程非常重要。

假設(shè)我們希望以 artistName 作為 Key,獲得歌曲列表作為 Value,則代碼實(shí)現(xiàn)如下:

@MapInfo(keyColumn = "artistName")@Query("SELECT * FROM Artist JOIN Song ON Artist.artistName = Song.songArtistName")fungetArtistNameToSongs():Map>,>,>,>
在該示例中,artistName 用作 Key,音樂人被映射到其歌曲名稱列表,最后 artistName 被映射到其歌曲名稱列表。

MapInfo 注解使您可以靈活地使用特定列,而不是整個(gè) data 類從而進(jìn)行更加自定義的映射。

其他優(yōu)勢

關(guān)系查詢方法的另一個(gè)好處是支持更多的數(shù)據(jù)操作,可以通過這個(gè)新功能來支持分組、篩選等功能。示例代碼如下:
@MapInfo(valueColumn = "songCount")@Query("    SELECT *, COUNT(songId) as songCount FROM Artist JOIN Song ON    Artist.artistName = Song.songArtistName    GROUP BY artistName WHERE songCount = 2")fungetArtistAndSongCountMap():Map,>

最后需要注意多重映射是一個(gè)核心返回類型,可以使用 Room 已經(jīng)支持的各種可觀察類型封裝 (包括 LiveData、Flowable、Flow)。因此,關(guān)系查詢方法可讓您輕松地在數(shù)據(jù)庫中定義任意數(shù)量的關(guān)聯(lián)關(guān)系。

更多新功能

內(nèi)置 Enum 類型轉(zhuǎn)換器

現(xiàn)在,如果系統(tǒng)未提供任何類型轉(zhuǎn)換器,Room 將默認(rèn)使用 "枚舉 - 字符串" 雙向類型轉(zhuǎn)換器。如果已存在適用于枚舉的類型轉(zhuǎn)換器,Room 將優(yōu)先使用該轉(zhuǎn)換器,而不使用默認(rèn)轉(zhuǎn)換器。

支持查詢回調(diào)現(xiàn)在,Room 提供了一個(gè)通用 callback API RoomDatabase.QueryCallback,此 API 會在執(zhí)行查詢時(shí)被調(diào)用,這將非常有助于我們在 Debug 模式下記錄日志??赏ㄟ^ RoomDatabase.Builder#setQueryCallback() 設(shè)置此回調(diào)。

如果您希望記錄查詢以了解數(shù)據(jù)庫中發(fā)生了什么,該功能可以幫助您進(jìn)行記錄,示例代碼如下:
fun setUp() {    database = databaseBuilder.setQueryCallback(        RoomDatabase.QueryCallback{ sqlQuery, bindArgs ->            // 記錄所有觸發(fā)的查詢            Log.d(TAG, "SQL Query $sqlQuery")        },        myBackgroundExecutor    ).build()}

支持原生 Paging 3.0 API

Room 現(xiàn)在支持為返回值類型為 androidx.paging.PagingSource 且?guī)?@Query 注解的方法生成實(shí)現(xiàn)。

支持 RxJava3

Room 現(xiàn)在支持 RxJava3 類型。通過依賴 androidx.room:room-rxjava3,您可以聲明返回值類型為 Flowable、Single、Maybe 和 Completable 的 DAO 方法。

支持 Kotlin Symbol Processing (KSP)

KSP 用于替代 KAPT,它能夠在 Kotlin 編譯器上以原生方式運(yùn)行注解處理器,從而顯著縮短構(gòu)建時(shí)間。

對于 Room,使用 KSP 有如下好處:

  • 提高 2 倍的構(gòu)建速度;
  • 直接處理 Kotlin 代碼,更好的支持空安全。

隨著 KSP 的穩(wěn)定,Room 將使用其功能實(shí)現(xiàn) value 類、生成 Kotlin 代碼等。

從 KAPT 遷移到 KSP 非常簡單,只需使用 KSP 插件替換 KAPT 插件,并使用 KSP 配置 Room 注解處理器,示例代碼如下:

plugins{    // 使用 KSP 插件替換 KATP 插件    // id("kotlin-kapt")     id("com.google.devtools.ksp")} dependencies{    // 使用 KSP 配置替代 KAPT    // kapt "androidx.room$version"    ksp "androidx.room$version"}

總結(jié)

自動(dòng)化遷移、關(guān)系查詢方法、KSP——Room 帶來了很多新功能,希望大家和我們一樣對所有這些 Room 更新感到興奮,記得查看并開始在您的應(yīng)用中使用這些新功能!

原文標(biāo)題:深入探討 Room 2.4.0 的最新進(jìn)展

文章出處:【微信公眾號:谷歌開發(fā)者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

審核編輯:湯梓紅


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • Google
    +關(guān)注

    關(guān)注

    5

    文章

    1754

    瀏覽量

    57380
  • 設(shè)備
    +關(guān)注

    關(guān)注

    2

    文章

    4453

    瀏覽量

    70494
  • 自動(dòng)化
    +關(guān)注

    關(guān)注

    29

    文章

    5483

    瀏覽量

    79008

原文標(biāo)題:深入探討 Room 2.4.0 的最新進(jìn)展

文章出處:【微信號:Google_Developers,微信公眾號:谷歌開發(fā)者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    深入了解示波器

    深入了解示波器
    發(fā)表于 11-14 22:32

    專家開講:深入了解電池技術(shù) ──Part 1

    。筆者不會一一詳細(xì)介紹所有的電池技術(shù),只選擇一些常見或是值得認(rèn)識的;而在接下來的專欄里,筆者將開始介紹電池分類、常見規(guī)格以及專業(yè)術(shù)語,如果你有特別想知道的電池技術(shù),歡迎留言!擴(kuò)展閱讀:專家開講:深入了解
    發(fā)表于 08-18 09:33

    專家開講:深入了解電池技術(shù)──Part 3

    資深工程師 Ivan Cowie 的「深入了解電池技術(shù)」專欄Part 3來啰!這次要介紹的是鉛酸電池(lead-acidbatteries)技術(shù)。鉛酸電池是在1859年由法國物理學(xué)家Gaston
    發(fā)表于 08-18 09:37

    單片機(jī)的深入了解

    項(xiàng)目名稱:單片機(jī)的深入了解!項(xiàng)目是否開源:否申請開發(fā)板數(shù)量:1 塊申請人團(tuán)隊(duì)介紹:我們團(tuán)隊(duì)由五個(gè)人組成,我們打算開始著手單片機(jī)的程序改編,設(shè)計(jì)一些比較特殊新穎的東西!希望給以支持!
    發(fā)表于 10-12 20:00

    深入了解LabVIEW FPGA資料分享

    深入了解LabVIEW FPGA
    發(fā)表于 05-27 08:35

    Zigbee各版本對比,讓你深入了解

    Zigbee各版本對比,讓你深入了解ZigBee是基于IEEE802.15.4標(biāo)準(zhǔn)的低功耗局域網(wǎng)協(xié)議。根據(jù)國際標(biāo)準(zhǔn)規(guī)定,ZigBee技術(shù)是一種短距離、低功耗的無線通信技術(shù)。這一名稱(又稱紫蜂協(xié)議
    發(fā)表于 02-29 11:24

    深入了解示波器(入門手冊),pdf版本

    本帖最后由 alpha007 于 2016-10-24 14:49 編輯 深入了解示波器(入門手冊),pdf版本
    發(fā)表于 07-07 09:53

    Hanlp1.7版本新增功能一覽

    `Hanlp1.7版本在去年下半年的時(shí)候就隨大快的DKH1.6版本同時(shí)發(fā)布了,截至目前1.7大版本也更新到了1.7.1了。本篇分別就1.7.0和1.7.1中新增
    發(fā)表于 03-22 09:56

    示波器的深入了解

    示波器的深入了解 引言自然界運(yùn)行著各種形式的正弦波,比如海浪、地震、聲波、爆破、空氣中傳播的聲音,或者身體運(yùn)轉(zhuǎn)的自然節(jié)律。物理世界里,能
    發(fā)表于 11-04 11:53 ?52次下載
    示波器的<b class='flag-5'>深入了解</b>

    深入了解示波器入門手冊

    深入了解示波器入門手冊
    發(fā)表于 03-27 17:43 ?241次下載
    <b class='flag-5'>深入了解</b>示波器入門手冊

    深入了解電路噪聲的那些事

    模擬電子的相關(guān)知識學(xué)習(xí)教材資料——深入了解電路噪聲的那些事
    發(fā)表于 09-27 15:19 ?0次下載

    深入了解電感與磁珠的異同

    模擬電子的相關(guān)知識學(xué)習(xí)教材資料——深入了解電感與磁珠的異同
    發(fā)表于 09-27 15:19 ?0次下載

    帶你深入了解示波器

    帶你深入了解示波器
    發(fā)表于 02-07 14:26 ?19次下載

    深入了解安全光柵

    深入了解安全光柵
    的頭像 發(fā)表于 06-25 13:53 ?1139次閱讀
    <b class='flag-5'>深入了解</b>安全光柵

    深入了解 GaN 技術(shù)

    深入了解 GaN 技術(shù)
    的頭像 發(fā)表于 12-06 17:28 ?6033次閱讀
    <b class='flag-5'>深入了解</b> GaN 技術(shù)