Jetpack Room数据库

Jetpack Room数据库

简介
Room 在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库。
处理大量结构化数据的应用可极大地受益于在本地保留这些数据。最常见的用例是缓存相关数据。这样,当设备无法访问网络时,用户仍可在离线状态下浏览相应内容。设备重新连接到网络后,用户发起的所有内容更改都会同步到服务器。
由于 Room 负责为您处理这些问题,因此我们强烈建议您使用 Room(而不是SQLite)。

Room架构图

依赖(AndroidX环境下)
在这里插入图片描述
在kotlin中使用需要添加kapt插件,在app的build.gradle文件的最上方添加如下代码:

apply plugin: 'kotlin-kapt'

然后在app的build.gradle文件中添加如下代码:

dependencies {
    ......你的其他依赖
    
    def room_version = "2.2.5"
    implementation "androidx.room:room-runtime:$room_version"
    //kotlin下使用
    kapt "androidx.room:room-compiler:$room_version"
    //java下使用
    //annotationProcessor "androidx.room:room-compiler:$room_version"
    
    //可选-Kotlin扩展和协程对Room的支持
    implementation "androidx.room:room-ktx:$room_version"
    
    //可选-RxJava对Room的支持
    implementation "androidx.room:room-rxjava2:$room_version"
    
    //可选-Guava对Room的支持,包括Optional和ListenableFuture
    implementation "androidx.room:room-guava:$room_version"
    
    //可选-需要用到相关测试工具的话
    testImplementation "androidx.room:room-testing:$room_version"
}

注意:避免出现Schema export directory is not provided警告,还需添加:

defaultConfig {
    //指定room.schemaLocation生成的文件路径  处理Room 警告 Schema export Error
    javaCompileOptions {
        annotationProcessorOptions {
            arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
        }
    }
}

Entity 实体类

@Entity(tableName = "users",primaryKeys = ["user_name","user_age"])
data class User(
    @PrimaryKey(autoGenerate = true) val id: Long,
    @ColumnInfo(name = "user_name") val name: String,
    @ColumnInfo(name = "user_age") val age: Int,
    @ColumnInfo val onLine: Boolean,
    @Ignore val remark: String
)

@Entity:定义表名、复合主键、索引等

  • tableName:设置表名字。默认是类的名字。
  • indices:设置索引。
  • inheritSuperIndices:父类的索引是否会自动被当前类继承。
  • primaryKeys:设置联合主键。
  • foreignKeys:设置外键。
  • ignoredColumns : 被忽略的字段。

@PrimaryKey:定义主键,autoGenerate设置是否自增
@ColumnInfo:定义字段名,name设置表中字段名,不设置默认为属性名
@Ignore:定义属性不被创建在表中

Dao 数据访问类

@Dao
interface UserDao {
    //查询所有用户
    @Query("select * from users")
    fun getUsers(): List<User>

    //根据ID查询用户
    @Query("select * from users where id = :id")
    fun getUserById(id: Long): User

    //根据用户名模糊查询用户
    @Query("select * from users where user_name Like '%' || :name ||'%'")
    fun getUsersByName(name: String): List<User>

    //根据用户名和年龄查询用户
    @Query("select * from users where user_name =:name and user_age >:age")
    fun getUsersByNameAndAge(name: String, age: Int): List<User>

    //插入用户
    /*  
        onConflict:默认值是OnConflictStrategy.ABORT,表示当插入有冲突的时候的处理策略。
                    OnConflictStrategy封装了Room解决冲突的相关策略:
       1. OnConflictStrategy.REPLACE:冲突策略是取代旧数据同时继续事务。
       2. OnConflictStrategy.ROLLBACK:冲突策略是回滚事务。
       3. OnConflictStrategy.ABORT:冲突策略是终止事务。
       4. OnConflictStrategy.FAIL:冲突策略是事务失败。
       5. OnConflictStrategy.IGNORE:冲突策略是忽略冲突。
     */
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun addUsers(users: List<User>)

    //更新用户
    @Update
    fun updateUsers(users: List<User>)

    //删除用户
    @Delete
    fun deleteUser(user: User)

    //根据条件删除用户
    @Query("delete from users where id = :id")
    fun deleteUserById(id: Long)

}

Database 单例数据库

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {

    abstract fun userDao(): UserDao

    companion object {
        private var instance: AppDatabase? = null
        fun getInstance(context: Context): AppDatabase {
            if (instance == null) {
                instance = Room.databaseBuilder(
                        context.applicationContext,
                        AppDatabase::class.java,
                        "data.db"
                ).allowMainThreadQueries().build()
            }
            return instance as AppDatabase
        }
    }
}

entities:数据库相关的所有Entity实体类,他们会转化成数据库里面的表。
可以传多个。例如:entities = [User::class,User1::class]
version:数据库版本。

数据库升级
当我们更新数据库表结构或新增表数据的时候,我们需要保留现有的数据,这时,我们需要对数据库进行更新,Room 支持通过 Migration 类进行增量迁移,以满足此需求。
具体操作如下:

  • 更新数据库版本
  • 创建Migration
  • 添加Migration到数据库
@Database(entities = [User::class], version = 2)
abstract class AppDatabase : RoomDatabase() {

    abstract fun userDao(): UserDao

    companion object {
        private var instance: AppDatabase? = null
        fun getInstance(context: Context): AppDatabase {
            if (instance == null) {
                instance = Room.databaseBuilder(
                        context.applicationContext,
                        AppDatabase::class.java,
                        "data.db"
                ).allowMainThreadQueries()
                    .addMigrations(MIGRATION_1_2)
                    .build()
            }
            return instance as AppDatabase
        }

        //给User表添加一个mobile字段
        private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("ALTER TABLE User " + " ADD COLUMN mobile TEXT")
            }
        }
    }
}

基本使用

val users = listOf(
    User(1, "张三", 20, true, "123456", ""),
    User(2, "李四", 22, true, "123456", "")
)
//插入
AppDatabase.getInstance(this)
    .userDao()
    .addUsers(users)

//查询
AppDatabase.getInstance(this)
    .userDao()
    .getUsers()

val updateUsers = listOf(
    User(1, "张三1", 20, true, "123456", ""),
    User(2, "李四2", 22, true, "123456", "")
)
//更新
AppDatabase.getInstance(this)
    .userDao()
    .updateUsers(updateUsers)

//删除
AppDatabase.getInstance(this)
    .userDao()
    .deleteUser(User(1, "张三1", 20, true, "123456", ""))

遇到的一些问题

  • 编译警告 Incremental annotation processing requested

    原因
    这是 Kotlin 1.3.50 的 bug,自 1.3.31 起,kapt 支持增量注解处理

    解决方法

1.版本降级

	使用 1.3.41 或以下版本

2.禁用增量编译

	在项目根目录下的 gradle.properties 文件中,
	添加 `kapt.incremental.apt=false`
  • 编译警告 Schema export directory is not provided to the annotation
    processor so we cannot export…

    原因
    没有指定room.schemaLocation生成的文件路径

    解决办法

1.给RoomDatabase设置exportSchema注解为false

@Database(entities = [User::class], version = 2, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {

2.指定room.schemaLocation生成的文件路径

defaultConfig {
    //指定room.schemaLocation生成的文件路径  处理Room 警告 Schema export Error
    javaCompileOptions {
        annotationProcessorOptions {
            arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
您好,以下是实现安卓开发 compose 现在有一个List<Note> 要实现拖动排序功能jetpack room数据库kotlin 代码示例: 首先,您需要在 build.gradle 文件中添加以下依赖: ``` implementation "androidx.compose.foundation:foundation-layout:1.0.0-beta02" implementation "androidx.compose.material:material:1.0.0-beta02" implementation "androidx.compose.runtime:runtime-livedata:1.0.0-beta02" implementation "androidx.compose.ui:ui:1.0.0-beta02" implementation "androidx.compose.ui:ui-tooling:1.0.0-beta02" implementation "androidx.room:room-runtime:2.3.0" kapt "androidx.room:room-compiler:2.3.0" ``` 然后,您可以使用 Jetpack Compose 实现一个可拖动的列表,并使用 Room 数据库存储和加载数据。以下是完整的 Kotlin 代码: ``` import androidx.compose.foundation.background import androidx.compose.foundation.gestures.draggable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey import androidx.room.Room import androidx.room.RoomDatabase import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @Entity(tableName = "notes") data class Note( @PrimaryKey val id: Int, @ColumnInfo(name = "text") val text: String, @ColumnInfo(name = "position") var position: Int ) @Dao interface NoteDao { @Query("SELECT * FROM notes ORDER BY position ASC") fun getNotes(): LiveData<List<Note>> @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insert(note: Note) @Update suspend fun update(note: Note) } @Database(entities = arrayOf(Note::class), version = 2) abstract class AppDatabase : RoomDatabase() { abstract fun noteDao(): NoteDao companion object { private var instance: AppDatabase? = null fun getInstance(context: Context): AppDatabase { return instance ?: synchronized(this) { instance ?: buildDatabase(context).also { instance = it } } } private fun buildDatabase(context: Context): AppDatabase { return Room.databaseBuilder(context, AppDatabase::class.java, "notes.db") .addMigrations(object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL("ALTER TABLE notes ADD COLUMN position INTEGER DEFAULT 0") } }) .build() } } } class NoteViewModel : ViewModel() { private val appDatabase = AppDatabase.getInstance(MyApplication.context) private val noteDao = appDatabase.noteDao() private val _notes = MutableLiveData<List<Note>>() init { loadNotes() } fun getNotes(): LiveData<List<Note>> { return _notes } fun addNote() { viewModelScope.launch(Dispatchers.IO) { val count = noteDao.getNotes().value?.size ?: 0 noteDao.insert(Note(count + 1, "Note ${count + 1}", count + 1)) } } fun updateNotePosition(note: Note, position: Int) { viewModelScope.launch(Dispatchers.IO) { note.position = position noteDao.update(note) } } private fun loadNotes() { viewModelScope.launch(Dispatchers.IO) { val notes = noteDao.getNotes().value ?: emptyList() _notes.postValue(notes) } } } @Composable fun NotesList(noteViewModel: NoteViewModel) { val notes by noteViewModel.getNotes().observeAsState(listOf()) Column(modifier = Modifier.padding(16.dp)) { Button(onClick = { noteViewModel.addNote() }) { Text("Add Note") } for (i in notes.indices) { val note = notes[i] Box( modifier = Modifier .fillMaxSize() .alpha(if (note.position == i) 1f else 0.5f) .background(Color.White) .draggable( orientation = Orientation.Vertical, onDragStarted = { /* Do nothing */ }, onDragStopped = { noteViewModel.updateNotePosition(note, it) } ) ) { Text( text = note.text, modifier = Modifier.padding(16.dp) ) } } } } class MainActivity : ComponentActivity() { private val noteViewModel by viewModels<NoteViewModel>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { NotesList(noteViewModel) } } } ``` 代码说明: 1.定义 Note 实体类,其中包含 id、text 和 position 字段。 2.定义 NoteDao 接口,其中包含 getNotes()、insert() 和 update() 函数。 3.AppDatabase 是一个 Room 数据库,它包含 NoteDao。 4.NoteViewModel 是一个 ViewModel,它包含一个 LiveData 列表,用于存储 Note 对象列表。 5.NotesList 是一个 Composable 函数,它显示 Note 对象列表,并允许用户重新排序它们。 6.在主 Activity 中使用 NotesList Composable 函数。 该代码依赖于 Jetpack Compose 和 Room 数据库Jetpack Compose 提供了一种简单的方法来实现可拖动的列表,而 Room 数据库用于保存和加载 Note 数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值