java中怎么在room添加物品_Room使用简介

Room是Jetpack中的ORM组件。Room可以简化SQLite数据库操作。Room包含3个主要的组件:

Entity。Entity是实体类,代表数据库里的一张表。

DAO。DAO提供了访问数据库的接口,返回Entity或Entity集合。

Database。Database是Entity和DAO的集合,代表一个SQLite数据库。Database是我们访问DAO和Entity的入口。

Entity

Entity是实体类,代表一个数据表。我们首先看一个简单的例子:

@Entity(tableName="users")

data class User (

@PrimaryKey

var uid: Int,

@ColumnInfo(name = "first_name")

var firstName: String?,

@ColumnInfo(name = "last_name")

var lastName: String?

@Ignore

var picture: Bitmap?

)

注解

说明

@Entity

声明实体类。

@PrimaryKey

声明主键。

@ColumnInfo

声明字段在数据表中的属性。

@Ignore

禁止将字段映射到数据表。

Room要求实体类必须拥有主键,且主键必须是Int或Long型。@ColumnInfo声明了列名和域名的对照关系。如果列名和域名相同,可以省略这个注解。上面这个Entity对应的SQL模式就是:

CREATE TABLE users (

INT uid PRIMARY KEY,

TEXT first_name,

TEXT last_name

);

可以看到,从Entity到SQL的映射是非常直观的。

实体类的域可以拥有默认值。实体类除了作为数据容器之外,也可以具有行为。参考下面的例子:

@Entity(tableName = "plants")

data class Plant(

@PrimaryKey @ColumnInfo(name = "id")

val plantId: String,

val name: String,

val description: String,

val growZoneNumber: Int,

val wateringInterval: Int = 7,

val imageUrl: String = ""

) {

fun shouldBeWatered(since: Calendar, lastWateringDate: Calendar) =

since > lastWateringDate.apply { add(DAY_OF_YEAR, wateringInterval) }

override fun toString() = name

}

Entity告诉Room如何在Java对象和SQL记录之间进行转换。然而要从SQLite数据库中得到Java对象,我们还需要Dao。

Dao

还是从例子入手。

@Dao

interface UserDao {

@Query("SELECT * FROM user")

fun getAll(): List

@Query("SELECT * FROM user WHERE uid IN (:userIds)")

fun loadAllByIds(userIds: IntArray): List

@Query("SELECT * FROM user WHERE first_name LIKE :first AND last_name LIKE :last LIMIT 1")

fun findByName(first: String, last: String): User

@Insert

suspend fun insertAll(vararg users: User)

@Delete

suspend fun delete(user: User)

}

注解

说明

@Dao

声明接口是DAO。

@Query

将SQL查询语句映射为Java方法。

@Insert

将SQL插入语句映射为Java方法。

@Delete

将SQL删除语句映射为Java方法。

从例子里可以看出,DAO和Entity有两个区别,首先Entity是类,而DAO是接口。其次,Entity将Java对象映射为SQL记录,将域映射为数据表中的列;DAO将SQL语句映射为Java方法。我们不需要手动编写这些方法,Room会自动生成它们。

数据库查询会引发磁盘IO,这是一个耗时操作。为了避免ANR,需要将数据库查询放到后台线程里执行。很多时候我们需要根据查询结果来更新界面,而界面必须在主线程中修改。那么如何将后台线程查询出的数据传递给主线程呢?你可以自己编写Handler,更简单的办法是让查询方法返回LiveData。

@Dao

interface PlantDao {

@Query("SELECT * FROM plants ORDER BY name")

fun getPlants(): LiveData>

@Query("SELECT * FROM plants WHERE growZoneNumber = :growZoneNumber ORDER BY name")

fun getPlantsWithGrowZoneNumber(growZoneNumber: Int): LiveData>

@Query("SELECT * FROM plants WHERE id = :plantId")

fun getPlant(plantId: String): LiveData

@Insert(onConflict = OnConflictStrategy.REPLACE)

fun insertAll(plants: List)

}

这里简单介绍一下LiveData。LiveData是一个为更新界面而定制的Observable,它将后台线程的数据投递到主线程。为了避免过度渲染,LiveData只在Activity或Fragment活跃的时候才投递数据。

如果使用kotlin进行开发,可以将DAO方法声明为suspend,配合viewModelScope使用。

Database

Database是Entity和DAO的集合,也是访问Entity和DAO的入口。Database是一个抽象类,每个DAO由一个抽闲方法返回。

@Database(entities = [User::class], version = 1)

abstract class AppDatabase: RoomDatabase() {

abstract fun userDao(): UserDao

}

此外Entity必须在@Database中进行注册。

实际的Database类也是由Room生成的。通过Room.databaseBuilder可以构造Database类。

val db = Room.databaseBuilder(

applicationContext,

AppDatabase::class.java,

"database-name"

).build()

综合起来,Room的用法可以总结为:

用Entity封装数据记录,用DAO映射查询语句。

通过databaseBuilder得到Database,通过Database得到DAO,通过DAO管理Entity。

Room插件

Room会自动生成类,这个动作是在编译期完成的,因为我们需要引入编译插件。

apply plugin: 'kotlin-kapt'

dependencies {

def room_version = "2.1.0-alpha04"

kapt "android.arch.persistence.room:compiler:$room_version"

implementation "androidx.room:room-runtime:$room_version"

implementation "androidx.room:room-ktx:$room_version"

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.0-alpha'

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.0-alpha'

implementation 'androidx.room:room-runtime:2.1.0-alpha06'

kapt 'androidx.room:room-compiler:2.1.0-alpha06'

implementation 'androidx.room:room-ktx:2.1.0-alpha06'

}

常见问题

DatabaseBuilder的callback未被调用

Room底层使用了SQLiteOpenHelper,只有当数据库被实际使用时,数据库才会被建立,回调函数才被调用。如果要手动调用callback,可以执行

// and then

db.beginTransaction()

db.endTransaction()

// or query a dummy select statement

db.query("select 1", null)

return db

Room检查表结构的方法

Room的createFromAsset使用PRAGMA tableinfo('tbl')来得到表的结构,并生成TableInfo实例。将这个实例和由Entity类生成的TableInfo进行比对,如果不一致,抛出IllegalStateException异常。

"Migration didn't properly handle XXX

tableinfo为每个列生成一行,记录了列的编号、名字、数据类型、是否可为NULL、默认值、列在主键中的顺序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值