Android數(shù)據(jù)庫Room的實際使用過程總結
前言
最近我負責開發(fā)一個基于Android系統(tǒng)的平板應用程序,在項目中涉及到數(shù)據(jù)庫操作的部分,我們最終決定采用Room數(shù)據(jù)庫框架來實現(xiàn)。在實際使用過程中,我遇到了一些挑戰(zhàn)和問題,現(xiàn)在我想將這些經驗記錄下來,以便未來參考和改進。
一、Room的基本使用
1.項目配置
在開發(fā)這個Android項目時,我決定將數(shù)據(jù)庫操作代碼獨立成一個模塊,這樣做有助于保持代碼的整潔和模塊化。在這個模塊中,我選擇了Kotlin作為編程語言,并使用了Kotlin 1.5.21版本。為了支持Kotlin開發(fā)和編譯,我需要在項目中包含兩個插件:kotlin-android 和 kotlin-kapt。這兩個插件分別負責Kotlin代碼的Android特定功能支持和注解處理,確保代碼能夠正確編譯和運行。
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
}采用了Room框架,具體版本為2.3.0。由于Room框架在不同版本之間可能存在API差異,因此在這里特別指出我所使用的版本,以便于在遇到問題時能夠準確地查找和解決問題,同時也使用到了協(xié)程,所有依賴如下:
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
// Room數(shù)據(jù)庫版本
def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version"
// Kapt
kapt "androidx.room:room-compiler:$room_version"
// room-ktx
implementation "androidx.room:room-ktx:$room_version"
// 協(xié)程
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
}
2.創(chuàng)建實體類(Entity)
在Room數(shù)據(jù)庫框架中,實體類是用來映射數(shù)據(jù)庫表的。每個實體類代表一個數(shù)據(jù)庫表,而實體類的屬性則對應表中的列。以下是一個使用Kotlin語言編寫的Airport實體類的示例代碼,其中id字段被標記為主鍵:
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "airports") // 指定表名
data class Airport(
@PrimaryKey(autoGenerate = true) val id: Int, // 主鍵,自動生成
val name: String, // 機場名稱
val city: String, // 所在城市
val country: String // 所在國家
)
3.創(chuàng)建數(shù)據(jù)訪問對象(DAO - Data Access Object)
DAO 用于定義訪問數(shù)據(jù)庫的方法,比如插入、查詢、更新、刪除等操作。以下是針對 Airport實體類創(chuàng)建的 AirportDao示例:
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import androidx.room.Delete
@Dao
interface AirportDao {
// 插入單個Airport對象
@Insert
suspend fun insert(airport: Airport)
// 插入多個Airport對象
@Insert
suspend fun insertAll(vararg airports: Airport)
// 根據(jù)ID查詢Airport對象
@Query("SELECT * FROM airports WHERE id = :id")
suspend fun getAirportById(id: Int): Airport?
// 更新Airport對象
@Update
suspend fun update(airport: Airport)
// 刪除單個Airport對象
@Delete
suspend fun delete(airport: Airport)
// 刪除所有Airport對象
@Query("DELETE FROM airports")
suspend fun deleteAll()
}
在這個AirportDao接口中:
- @Dao 注解標記這個接口為一個DAO接口。
- @Insert注解用于定義插入操作的方法。insert()方法可以插入單個Airport對象,而insertAll()方法可以插入多個Airport對象。
- @Query 注解用于定義自定義SQL查詢的方法。getAirportById()方法通過ID查詢單個Airport對象。
- @Update 注解用于定義更新操作的方法。update()方法更新一個Airport對象。
- @Delete注解用于定義刪除操作的方法。delete()方法可以刪除單個Airport對象,而deleteAll()方法可以刪除所有Airport對象。
- suspend關鍵字用于標記一個函數(shù)為掛起函數(shù)(suspend function),這是Kotlin協(xié)程(coroutines)的一個重要特性。掛起函數(shù)可以暫停和恢復其執(zhí)行,而不會阻塞線程
這些方法定義了與Airport實體類對應的數(shù)據(jù)庫表進行交互的基本操作。Room框架會在編譯時自動實現(xiàn)這些接口方法,開發(fā)者無需手動編寫實現(xiàn)代碼。
4. 創(chuàng)建數(shù)據(jù)庫抽象類(Database)
在Room數(shù)據(jù)庫框架中,你需要創(chuàng)建一個繼承自RoomDatabase的抽象類,這個類將作為數(shù)據(jù)庫的訪問入口,并定義與實體類和DAO的關聯(lián)。以下是一個示例代碼,展示了如何創(chuàng)建這樣的數(shù)據(jù)庫類,并與Airport實體類和AirportDao接口關聯(lián):
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
// 定義數(shù)據(jù)庫的版本
@Database(entities = [Airport::class], version = 1, exportSchema = false)
@TypeConverters(YourTypeConverters::class) // 如果有自定義類型轉換器,在這里指定
abstract class AppDatabase : RoomDatabase() {
// 提供獲取DAO實例的方法
abstract fun airportDao(): AirportDao
// Companion object to create an instance of AppDatabase
companion object {
// Singleton instance of the database
@Volatile
private var instance: AppDatabase? = null
// Method to get the database instance
fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) {
instance ?: buildDatabase(context).also { inst ->
instance = inst
}
}
}
// Method to build the database
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_database"
).build()
}
}
}
在這個AppDatabase類中:
- @Database注解定義了數(shù)據(jù)庫包含的實體類(entities)和數(shù)據(jù)庫版本(version)。exportSchema屬性用于控制是否導出數(shù)據(jù)庫的schema文件,通常在開發(fā)階段設置為true,而在生產環(huán)境中設置為false。
- @TypeConverters注解用于指定一個或多個類,這些類包含自定義的類型轉換器,如果需要將非標準類型(如Date或URL)存儲在數(shù)據(jù)庫中,這些轉換器是必需的。
- abstract fun airportDao(): AirportDao提供了一個抽象方法,用于獲取AirportDao的實例,這樣我們就可以在數(shù)據(jù)庫類中執(zhí)行對Airport表的操作。
- companion
object提供了一個單例模式的實現(xiàn),用于獲取AppDatabase的實例。getInstance()方法確保整個應用中只有一個數(shù)據(jù)庫實例被創(chuàng)建。buildDatabase()方法用于實際構建和配置數(shù)據(jù)庫。
**請注意!**你需要將YourTypeConverters::class替換為實際包含自定義類型轉換器的類的名稱,如果你沒有自定義類型轉換器,可以省略@TypeConverters注解。此外,context參數(shù)需要從你的應用上下文傳遞給getInstance()方法,以確保數(shù)據(jù)庫正確地與應用的生命周期關聯(lián)。
5. 使用數(shù)據(jù)庫
在Android的Activity中使用數(shù)據(jù)庫進行操作時,可以在協(xié)程中執(zhí)行這些操作,以避免阻塞主線程。以下是在Activity中使用協(xié)程與Room數(shù)據(jù)庫進行交互的簡單示例代碼片段:
import android.os.Bundle
import android.util.Log
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import kotlinx.coroutines.*
class AirportActivity : AppCompatActivity() {
private val viewModel by viewModels<AirportViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_airport)
// 啟動協(xié)程來插入數(shù)據(jù)
lifecycleScope.launch {
viewModel.insertAirport(Airport(0, "Moonshot International", "Shanghai", "China"))
}
// 啟動協(xié)程來查詢數(shù)據(jù)
lifecycleScope.launch {
val airport = viewModel.getAirportById(1) // 假設ID為1
airport.observe(this@AirportActivity, { airport ->
Log.d("AirportActivity", "Airport Name: ${airport?.name}")
})
}
}
}
在這個Activity中:
- lifecycleScope是一個與Activity生命周期綁定的協(xié)程作用域,它確保協(xié)程在Activity銷毀時取消。
- launch是一個協(xié)程構建器,用于啟動一個新的協(xié)程。
- insertAirport方法在協(xié)程中被調用,用于插入新的機場信息。
getAirportById方法返回一個LiveData<Airport?>對象,它在協(xié)程中被觀察,以便在機場信息變化時更新UI。
請注意,AirportViewModel需要正確實現(xiàn),并且包含insertAirport和getAirportById方法。這些方法應該在ViewModel中使用viewModelScope而不是lifecycleScope,因為viewModelScope是與ViewModel的生命周期綁定的,而不是Activity。
以下是AirportViewModel的示例實現(xiàn):
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
class AirportViewModel : ViewModel() {
private val database = AppDatabase.getInstance(applicationContext) // 假設這是全局可訪問的context
private val airportDao = database.airportDao()
fun insertAirport(airport: Airport) {
viewModelScope.launch {
airportDao.insert(airport)
}
}
fun getAirportById(id: Int): LiveData<Airport?> {
return liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
emit(airportDao.getAirportById(id))
}
}
}
至此Room簡單的使用已經說完了,這些步驟構成了Room數(shù)據(jù)庫在Android應用中的簡單使用流程。Room提供了一個抽象層,幫助開發(fā)者以更聲明式和類型安全的方式進行數(shù)據(jù)庫操作,同時利用協(xié)程簡化了異步編程。
二、Room使用過程遇到的問題
1.聲明表中字段可以為null
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "airports") // 指定表名
data class Airport(
@PrimaryKey(autoGenerate = true) val id: Int, // 主鍵,自動生成
val name: String, // 機場名稱
val city: String, // 所在城市
val country: String // 所在國家
)
如果在使用Room數(shù)據(jù)庫時,需要在實體類中允許某些字段存儲空值,可以直接將這些字段聲明為可空類型。這樣,即使在插入數(shù)據(jù)時這些字段的值為空,數(shù)據(jù)庫操作也能正常進行。具體來說,只需在實體類中將相應的變量聲明為String?、Int?等可空類型,Room就會允許這些字段在數(shù)據(jù)庫中存儲空值,代碼如下:
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "airports") // 指定表名
class Airport {
@PrimaryKey(autoGenerate = true)
var id: Int = 0 // 主鍵,自動生成
var name: String? = null // 機場名稱
var city: String? = null// 所在城市
var country: String? = null // 所在國家
}
2.數(shù)據(jù)庫升級
當你在Room數(shù)據(jù)庫的實體類中添加了一個新的字段后,如果在運行應用時遇到了崩潰,并且出現(xiàn)了異常信息,這通常是因為Room數(shù)據(jù)庫的遷移問題。Room需要知道如何處理數(shù)據(jù)庫結構的變化,比如添加、刪除或修改字段。如果沒有正確處理這些變化,Room在嘗試訪問數(shù)據(jù)庫時就會拋出異常,異常信息如下:
Room cannot verify the data integrity, Looks like vou’ve changed schema but forgot to update the version number, You can simply . fix this by increasing the version number.
遇到數(shù)據(jù)庫結構變更時,通常有兩種處理方法:
第一種卸載并重新安裝應用:這是一種簡單直接的方法,通過卸載應用再重新安裝,應用將創(chuàng)建全新的數(shù)據(jù)庫,從而自動包含所有新的表結構和字段變更。另一種方法是進行數(shù)據(jù)庫升級,下面是數(shù)據(jù)庫升級的步驟:
- 更新實體類:在實體類中添加新的字段。例如,如果你想為Airport實體類添加一個新字段,你可以直接聲明這個字段為可空類型,如val newField: String? = null。
- 增加數(shù)據(jù)庫版本號:在@Database注解中增加版本號。例如,如果你的數(shù)據(jù)庫當前版本是1,那么在添加新字段后,將版本號增加到2:@Database(entities = [Airport::class], version = 2) 。
- 創(chuàng)建Migration遷移類:在RoomDatabase中定義Migration對象,指定如何從舊版本遷移到新版本。例如,為Airport實體類添加新字段的遷移可以這樣定義:
val MIGRATION_1_2: Migration = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
// 執(zhí)行SQL
database.execSQL("ALTER TABLE airports ADD COLUMN newField TEXT")
}
}
- 將Migration添加到數(shù)據(jù)庫構建中:在構建數(shù)據(jù)庫時,通過addMigrations方法添加Migration對象。例如
val database = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_database"
).addMigrations(MIGRATION_1_2).build()
這樣,當應用啟動時,Room會自動執(zhí)行Migration中定義的遷移操作。
通過這些步驟,你可以平滑地將Room數(shù)據(jù)庫升級到新版本,同時添加新的字段。如果用戶之前安裝的數(shù)據(jù)庫版本較低,Room會按照定義的Migration順序依次執(zhí)行,直到達到最新的數(shù)據(jù)庫版本。
3.如何關聯(lián)外鍵ForeignKey
發(fā)現(xiàn)有些人不知道什么是外鍵:這里簡單說明一下:
外鍵的主要作用如下:
建立關聯(lián)關系:用于在不同表之間建立聯(lián)系,清晰體現(xiàn)實體之間的對應關系,如機場與跑道的所屬關系,方便進行多表聯(lián)合查詢等操作。
維護數(shù)據(jù)完整性:防止在插入或更新數(shù)據(jù)時出現(xiàn)無效數(shù)據(jù),確保子表中的外鍵值在父表的主鍵值中存在或為 NULL,保證數(shù)據(jù)的準確性和一致性。
實現(xiàn)級聯(lián)操作:定義級聯(lián)規(guī)則,當父表中的記錄發(fā)生刪除或更新時,子表中對應的記錄可按規(guī)則自動進行相應操作,確保數(shù)據(jù)在不同表之間的協(xié)調一致。
約束數(shù)據(jù)變化:通過參照完整性約束,控制數(shù)據(jù)在表之間的更新和刪除傳播方式,保證數(shù)據(jù)的修改和更新符合特定的業(yè)務邏輯和要求。
在 Room 中聲明外鍵可以通過在實體類中使用@ForeignKey注解來實現(xiàn)。以下是一個示例,展示了如何在機場表和機場跑道表之間聲明外鍵關聯(lián):
- 定義機場表實體類
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "airport")
data class Airport(
@PrimaryKey(autoGenerate = true)
var airportId: Int = 0,
var airportName: String = ""
)
- 定義機場跑道表實體類(Runway)并聲明外鍵
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
@Entity(
tableName = "runway",
foreignKeys = [ForeignKey(
entity = Airport::class,
parentColumns = ["airportId"],
childColumns = ["airportIdFK"],
onDelete = ForeignKey.CASCADE
)]
)
data class Runway(
@PrimaryKey(autoGenerate = true)
var runwayId: Int = 0,
var airportIdFK: Int = 0,
var runwayName: String = ""
)
在上述 Runway 實體類中,使用 @ForeignKey 注解來聲明外鍵關系,各參數(shù)含義和 Java 版本中的一致:
- entity:指定關聯(lián)的實體類型,這里關聯(lián)的是 Airport 類。
- parentColumns:表示在關聯(lián)的父實體(即 Airport)中對應的主鍵列名,此處為 airportId。
- childColumns:代表在當前實體(Runway)中作為外鍵的列名,也就是 airportIdFK。
- onDelete:定義了當父表(Airport 表)中對應的主鍵記錄被刪除時的行為,這里設置為 CASCADE,意味著級聯(lián)刪除,比如刪除某個機場記錄時,與之關聯(lián)的跑道記錄也會自動刪除。除了 CASCADE 之外,還有以下幾種常見的類型及其含義:
-NO_ACTION含義:當父表中的記錄被刪除或更新時,子表中的外鍵列不做任何操作,這可能會導致子表中的外鍵引用無效的父鍵值,從而產生孤立的數(shù)據(jù),破壞數(shù)據(jù)的完整性。
示例:在 文章表 和 評論表 的關聯(lián)中,如果使用 NO_ACTION,當一篇文章被刪除時,評論表中對應的文章外鍵值不會改變,仍然保留原來的文章 ID,即使該文章已經不存在了,這就導致了評論表中的這些評論與實際不存在的文章產生了孤立的關聯(lián)。
SET_NULL含義:當父表中的記錄被刪除或更新時,子表中對應的外鍵列的值將被設置為 NULL。
示例:假設有 用戶表 和 訂單表,訂單表 中的 用戶ID 是外鍵關聯(lián)到 用戶表 的主鍵。當一個用戶被刪除時,該用戶的所有訂單記錄中的 用戶ID 字段將被設置為 NULL,表示這些訂單與任何用戶都不再關聯(lián),但訂單記錄本身仍然保留在 訂單表 中。
SET_DEFAULT含義:當父表中的記錄被刪除或更新時,子表中對應的外鍵列的值將被設置為其默認值。
示例:若 訂單表 中的 用戶ID 外鍵字段有一個默認值為 0,當關聯(lián)的用戶被刪除時,該用戶的所有訂單記錄中的 用戶ID 將被設置為 0,以此來表示一種特殊的狀態(tài)或無關聯(lián)的情況。
RESTRICT含義:當父表中的記錄被刪除或更新時,如果子表中存在對應的關聯(lián)記錄,則拒絕父表的刪除或更新操作,從而防止出現(xiàn)孤立的子記錄,確保數(shù)據(jù)的一致性和完整性。
示例:在 部門表 和 員工表 的關系中,員工表 通過外鍵關聯(lián)到 部門表 的主鍵。如果試圖刪除一個部門,而該部門下還有員工,那么由于 RESTRICT 約束,數(shù)據(jù)庫將不允許執(zhí)行這個刪除操作,避免出現(xiàn)員工所屬部門不存在的不合理情況。
4.使用事務@Transaction
在 Room 中,事務是一種重要的機制,用于確保多個數(shù)據(jù)庫操作的原子性,即要么所有操作都成功執(zhí)行,數(shù)據(jù)庫狀態(tài)被完整更新;要么所有操作都失敗回滾,數(shù)據(jù)庫保持初始狀態(tài),從而有效地維護數(shù)據(jù)的一致性。以下是關于 Room 中事務的詳細介紹:
事務的必要性
- 在實際的數(shù)據(jù)庫操作中,常常會有多個相關的操作需要作為一個整體來執(zhí)行。例如,在一個銀行轉賬系統(tǒng)中,從一個賬戶扣除一定金額并在另一個賬戶增加相應金額,這兩個操作必須同時成功或同時失敗,否則就會導致數(shù)據(jù)不一致,如賬戶余額出現(xiàn)錯誤等問題。事務機制正是為了滿足這種需求而設計的,它能夠保證在復雜的操作場景下數(shù)據(jù)的準確性和完整性。
使用方法
以下是一個使用事務進行多表查詢的例子,還以Airport和Runway這兩個實體類為例,它們之間存在關聯(lián)關系。
@Dao
interface AirportRunwayDao {
@Query("SELECT * FROM airports WHERE id = :airportId")
fun getAirport(airportId: Int): Airport?
@Query("SELECT * FROM runways WHERE airportId = :airportId")
fun getRunways(airportId: Int): List<Runway>
// 事務性查詢操作
@Transaction
fun getAirportWithRunways(airportId: Int): Pair<Airport?, List<Runway>> {
// 這里的代碼將在一個事務中執(zhí)行
val airport = getAirport(airportId)
val runways = getRunways(airportId)
return Pair(airport, runways)
}
}
5.數(shù)據(jù)庫文件的位置
在Room數(shù)據(jù)庫中,創(chuàng)建AppDatabase對象時,可以指定數(shù)據(jù)庫文件的名稱,這個名稱也是數(shù)據(jù)庫文件的名字。默認情況下,Room數(shù)據(jù)庫文件存儲在應用的內部存儲目錄下的特定子目錄中。如果需要更改數(shù)據(jù)庫文件的存儲位置,可以通過指定具體的文件路徑來實現(xiàn)。這樣,數(shù)據(jù)庫文件就會被創(chuàng)建在指定的路徑下,而不是默認的內部存儲位置。代碼如下:
private fun buildDatabase(context: Context): AppDatabase {
val dbPath = "${context.getExternalFilesDir(null)?.absolutePath}/database/test.db"
return Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
dbPath
).build()
}
這樣數(shù)據(jù)庫文件存在的位置,就會放到指定目錄下。
6.打開已存在的數(shù)據(jù)庫
在大多數(shù)應用場景中,Room數(shù)據(jù)庫的標準使用方法已經足夠。但在本次項目中,我們需要軟件具備打開本地已有數(shù)據(jù)庫文件或導入外部數(shù)據(jù)庫文件的功能。操作步驟與常規(guī)配置相似:
- 創(chuàng)建實體類(Entity):定義一個實體類來映射數(shù)據(jù)庫中的表結構。
- 創(chuàng)建數(shù)據(jù)訪問對象(DAO):定義一個接口,用于執(zhí)行數(shù)據(jù)庫的增刪改查等操作。
與常規(guī)使用的主要區(qū)別在于,需要將待打開的數(shù)據(jù)庫文件放置在指定目錄下。在初始化Room數(shù)據(jù)庫時,指定數(shù)據(jù)庫文件的路徑:
- 如果指定路徑下已存在數(shù)據(jù)庫文件,Room將直接使用該文件。
- 如果指定路徑下沒有數(shù)據(jù)庫文件,Room將創(chuàng)建一個新的數(shù)據(jù)庫文件。
這樣,我們就能夠實現(xiàn)對本地或外部數(shù)據(jù)庫文件的訪問和管理。
打開外部數(shù)據(jù)時遇到的問題
當遇到
IllegalStateException: Pre-packaged database has an invalid schema: airport
Expected…
…表結構信息
Found:
…表結構信息
當遇到類似 “IllagelStateException: Pre-packaged database has an invalid schena: Excepted… Found:” 這樣的報錯時,其背后的原因通常是預打包數(shù)據(jù)庫(也就是你準備打開的外部數(shù)據(jù)文件對應的數(shù)據(jù)庫)的架構與 Room 所期望的架構出現(xiàn)了不匹配的情況。
那這里所說的數(shù)據(jù)庫架構,涵蓋了表結構、列定義以及約束等多個方面的內容。常見的導致架構不匹配的因素有以下幾種:
- 一是字段可空聲明不一致。比如在 Room中通過實體類定義某個字段是非空的,但在預打包數(shù)據(jù)庫里對應的該字段卻允許為空,或者反之,這種差異就會造成架構不一致。
- 二是數(shù)據(jù)類型不一致??赡茉趯嶓w類中定義某個字段為 Integer 類型,然而預打包數(shù)據(jù)庫里對應列的數(shù)據(jù)類型卻是TEXT,不同的數(shù)據(jù)類型設置會讓 Room 在驗證數(shù)據(jù)庫架構時判定為不匹配。
- 三是外鍵約束不一致。例如在 Room 的實體類中定義了兩張表之間通過外鍵建立了特定的關聯(lián)關系,并且設置了相應的外鍵約束規(guī)則,像刪除操作時的級聯(lián)方式等,但在預打包數(shù)據(jù)庫里對應的表之間的外鍵約束情況與之不同,這同樣會引發(fā)架構方面的問題。
當出現(xiàn)這類報錯后,我們需要仔細對比異常日志里呈現(xiàn)的兩個表結構,查找究竟是哪個地方出現(xiàn)了不一致的情況。一旦發(fā)現(xiàn)了問題所在,接下來就要采取相應的解決措施。要么對 Room 中的 Entity 實體類進行修改,使其表結構、字段定義以及約束等各方面與預打包數(shù)據(jù)庫的實際架構相符;要么對預打包的數(shù)據(jù)庫文件本身進行調整,從而讓二者的結構能夠達成一致。只有在確保這兩個結構完全一致的前提下,才能夠成功連接數(shù)據(jù)庫,避免出現(xiàn)上述的報錯情況。
總結
到此這篇關于Android數(shù)據(jù)庫Room的實際使用的文章就介紹到這了,更多相關Android數(shù)據(jù)庫Room使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
android實現(xiàn)RecyclerView列表單選功能
這篇文章主要為大家詳細介紹了android實現(xiàn)RecyclerView列表單選功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-07-07
全面解析Android中對EditText輸入實現(xiàn)監(jiān)聽的方法
這篇文章主要介紹了Android中對EditText輸入實現(xiàn)監(jiān)聽的方法,包括一個仿iOS的帶清除功能的ClearEditText輸入框控件的詳細使用介紹,需要的朋友可以參考下2016-04-04
Android在項目中接入騰訊TBS瀏覽器WebView的教程與注意的地方
今天小編就為大家分享一篇關于Android在項目中接入騰訊TBS瀏覽器WebView的教程與注意的地方,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-10-10

