Room 概述
Room 持久性库在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库,具体来说,Room具有一下优势:
1、针对SQL 查询的编译时验证。
2、可最大限度减少重复和容易出错的样板代码的方便注解。
3、简化了数据库迁移路径。
build.gradle
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
dependencies {
// Room
implementation "androidx.room:room-ktx:2.4.1"
kapt "androidx.room:room-compiler:2.4.1"
//ViewModelScope + LifecycleScope + liveData
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0"
//json解析
implementation 'com.alibaba:fastjson:1.2.58'
}
主要组件
Room 包含三个主要组件:
1、数据库类,用于保存数据库并作用应用持久性数据底层连接的主要访问点。
2、数据实体,用于表示应用的数据库中的表。
3、数据访问对象(DAO),提供您的应用可用于查询、更新、插入和删除数据库中的数据的方法。
数据库类为应用提供与该数据库关联的 DAO 的实例。反过来,应用可以使用 DAO 从数据库中检索数据,作为关联数据实体对象的实例。此外,应用还可以使用定义的数据实体更新相对应表中的行,或者创建新行供插入。图1说明了 Room 的不同组件之间的关系。
数据实体
@Entity(tableName = "word_table")
data class Word(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id: Int = 0,
@ColumnInfo(name = "word")
val word: String
)
@Entity 使用 Room 定义一个数据实体 Word (带 Entity 注解的类),一个 Entity 表由主键和一个或者多个列组成,Word 中的每一个实例都代表着 word_table 中的一行,tableName 后面为表名,在不指定表名的情况下,默认将类名作为数据表的名称。Room默认使用字段名称作为列名称,如需更改,采用 @ColumnInfo注解设置 name 属性(列名)。
数据访问对象 (DAO)
@Dao
interface WordDao {
@Query("SELECT * FROM word_table ORDER BY word ASC")
suspend fun getAlphabetizedWords(): List<Word>
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(word: Word)
@Query("DELETE FROM word_table")
suspend fun deleteAll()
}
定义了一个 WordDao 的 DAO 。WorDao 提供了应用的其余部分用于与 word 表中的数据交互方法。
数据库
@Database(entities = [Word::class], version = 2)
abstract class AppDatabase : RoomDatabase() {
abstract fun wordDao(): WordDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
// if the INSTANCE is not null, then return it,
// if it is, then create the database
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"word_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
// return instance
instance
}
}
}
}
定义用于保存数据库的 AppDatabase 类,AppDatabase 定义数据库配置,并作为应用对持久性数据的主要访问点,数据库类必须满足一下条件:
1、该类必须带有 @Database 注解,该注解包含列出所有与数据库关联的数据实体的 entities 数组。
2、该类必须是一个抽象类,用于扩展 RoomDatabase.
3、对于与数据库关联的每一个 DAO类,数据库类必须定义一个具有零参数的抽象方法,并返回 DAO 类的实例。
MainActivity 使用
class MainActivity : AppCompatActivity() {
lateinit var database: AppDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
database = AppDatabase.getDatabase(this)
findViewById<Button>(R.id.btn1).setOnClickListener {
lifecycleScope.launch {
database.wordDao().insert(Word(word = "long"))
database.wordDao().insert(Word(word = "long"))
database.wordDao().insert(Word(word = "long"))
}
}
findViewById<Button>(R.id.btn2).setOnClickListener {
lifecycleScope.launch {
val list = database.wordDao().getAlphabetizedWords();
Log.i("TAG", JSON.toJSONString(list))
}
}
}
}
数据库迁移
@Database(entities = [Word::class, Device::class], version = 6)
abstract class AppDatabase : RoomDatabase() {
abstract fun wordDao(): WordDao
abstract fun deviceDao(): DeviceDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
// if the INSTANCE is not null, then return it,
// if it is, then create the database
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"word_database"
)
.fallbackToDestructiveMigration()
.addMigrations(object : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
//将数据表device创建出来
database.execSQL("CREATE TABLE 'device' ('id' TEXT,'location' TEXT,'deviceName' TEXT,'deviceType' TEXT,PRIMARY KEY ('id')) ");
}
},object :Migration(4,5){
override fun migrate(database: SupportSQLiteDatabase) {
//为device表增加一列
database.execSQL("ALTER TABLE device ADD COLUMN deviceCode TEXT NOT NULL DEFAULT 'a'");
}
},object :Migration(5,6){
override fun migrate(database: SupportSQLiteDatabase) {
//为device表增加一列
database.execSQL("ALTER TABLE device ADD COLUMN deviceManager TEXT NOT NULL DEFAULT 'A类型'");
}
})
.build()
INSTANCE = instance
// return instance
instance
}
}
}
}
addMigrations 增加对应升级的策略
参考:
使用 Room 将数据保存到本地数据库 | Android 开发者 | Android Developers
Android jetpack Room数据库(二)版本升级/迁移_java.lang.illegalstateexception: a migration from _肖波86440的博客-CSDN博客