自从Google推出了Room
,咱们能够优雅的使用sqlite数据库。
固然用Room
+Paging
的组合,代码写起来飞起来 关于Room
+Paging
的使用方法请参考下面的教程。
Paging在Android中的应用: juejin.im/post/5e75db…java
在App的build.gradle
的文件中添加Room
库的引用。android
def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-rxjava2:$room_version"
implementation "androidx.room:room-testing:$room_version"
implementation "androidx.room:room-ktx:$room_version"
复制代码
首先咱们要建立一个data class
做为数据库的Entity class。 而后使用下面介绍的注解添加关于数据库的额外信息。git
在想建立的entity上面添加@Entity
的注解。github
@Entity(tableName = "users_table")
data class User(...)
复制代码
还能够根据需求在@Entity
后面能够添加不少参数。sql
tableName
, 能够为Table起名字。示例,tableName = "users_table"
。primaryKeys
, 能够为Table指定主键。示例,primaryKeys = {"firstName", "lastName"}
。Index
, 为了加快数据的查询速度吗,能够添加索引。示例,indices = {@Index("lastName")
。unique
,在索引当中须要确保两个列中的信息的惟一性时能够添加。示例indices = {@Index(value = {"first_name", "last_name"},unique = true)}
@PrimaryKey
注解跟上面@Entity
中的primaryKeys
的做用是同样的。 针对自动增长的主键,还能够添加autoGenerate=true
。数据库
@PrimaryKey(autoGenerate = true)
val id: Int? = null,
复制代码
为entity中的属性添加列表名字name="name"
。app
@ColumnInfo(name = "birthday")
val birthday: String
复制代码
若是在entity中存在不想存入数据库的属性,能够添加忽略的注解@Ignore
。ide
@Ignore
val nationality: String
复制代码
若是在Entity类里面若是有其余的对象,可使用@Embedded
进行嵌套。固然要被嵌套的对象也须要是被@Entity
加上注解的Entity类。函数
@Embedded
val address: Address
复制代码
Dao
的全称是Data Access Object
,是数据访问对象是一个面向对象的数据库接口。在通常开发中须要单独抽象出一个Dao
。 在Room
中须要建立interface,并添加@Dao
注解。post
@Dao
interface UserDao {}
复制代码
须要在实现查询的方法上面添加@Query
,并加上要查询的SQL语句。
@Query("SELECT * FROM users_table where first_name = :firstName")
suspend fun getUserByFirstName(firstName:String): List<User>
复制代码
若是方法中有传入的参数须要在SQL查询语句中使用,能够用:parameter
来绑定参数。
要在数据库中插入数据时须要加上@Insert
的注解,可是不须要加上SQL语句。 须要把插入数据库的对象做为参数传入到函数中。
@Insert
suspend fun insertUser(users: List<User>)
复制代码
要在数据库中删除数据时须要加上@Delete
的注解,可是不须要加上SQL语句。
须要把删除的对象做为参数传入到函数中。
@Delete
suspend fun deleteUser(users: List<User>)
复制代码
要在数据库中更新数据时须要加上@Update
的注解,可是不须要加上SQL语句。 须要把更新的对象做为参数传入到函数中。
@Update
public void updateUsers(User... user);
复制代码
可使用@Transaction
的注解,添加SQLite的事务。
@Transaction
suspend fun deleteAllAndInsertUser(users: List<User>) {
deleteUser(getAll())
insertUser(users)
}
复制代码
@Dao
interface UserDao {
@Query("SELECT * FROM users_table")
suspend fun getAll(): List<User>
@Insert
suspend fun insertUser(user: User)
@Update
public void updateUsers(User... user);
@Delete
suspend fun deleteUser(users: List<User>)
@Transaction
suspend fun deleteAllAndInsertUser(users: List<User>) {
deleteUser(getAll())
users.forEach { insertUser(it) }
}
}
复制代码
示例代码以下:
@Database(version = 1, entities = [User::class]) // 添加Database的注解,还须要添加版本信息和entities信息
@TypeConverters(Converter::class) // 添加TypeConverter的注解
abstract class AppDatabase : RoomDatabase() {
companion object {
private const val DB_NAME = "user_database.db"
private var INSTANCE: AppDatabase? = null
private var lock = Any()
fun getInstance(context: Context): AppDatabase {
synchronized(lock) {
if (INSTANCE == null) {
// 第一个参数是Context, 第二个参数是DB的class,第三个参数是DB名字
INSTANCE =
Room.databaseBuilder(context, AppDatabase::class.java, DB_NAME).build()
}
return INSTANCE!!
}
}
fun destroyInstance() {
INSTANCE = null
}
}
abstract fun getUserDao(): UserDao
}
复制代码
数据库类须要继承RoomDatabase
,同时必须声明的是抽象类
。 还有须要注意的一点是,建立数据库的实例对性能的同样特别大,因此不能重复建立。针对这个问题广泛的作法是把建立实例的方法设计成Singleton模式
。
须要给数据库的类上面加上@Database
的注解。同时还须要不上下列信息。
version
,指定数据库的版本。entities
,须要指定全部的entity类。@Database(version = 1, entities = [User::class])
复制代码
Room是支持字符串和整型等的基本数据类型,可是遇到其余类型的数据类型时,咱们就须要用@TypeConverter
来进行数据类型的转换。好比User里面的生日的属性是Date时,就须要进行数据类型的转换。
class Converter {
@TypeConverter
fun longToDate(timeStamp: Long?): Date? {
if (timeStamp == null) return null
return Date(timeStamp)
}
@TypeConverter
fun dateToLong(date: Date?): Long? {
if (date == null) return null
return date.time
}
}
复制代码
当App已经发布之后遇到须要更新和改变数据库结构时,就须要用到数据库的数据迁移。Room为咱们提供了数据库升级的功能。
// 从版本1升级到版本2
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, `name` TEXT, " +
"PRIMARY KEY(`id`))")
}
}
// 从版本2升级到版本3
val MIGRATION_2_3 = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Book ADD COLUMN pub_year INTEGER")
}
}
// 添加版本升级到Room的builder中
Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3).build()
复制代码
Github: github.com/HyejeanMOON…
其余教程:
Android的属性动画(Property Animation)详细教程: juejin.im/post/5eb7a5…
Android ConstraintLayout的易懂教程: juejin.im/post/5ea50a…
在RecyclerView中能够应对多个ViewType的库--Groupie: juejin.im/post/5e9059…
Google的MergeAdapter的使用: juejin.im/post/5e903f…
Paging在Android中的应用: juejin.im/post/5e75db…
Android UI测试之Espresso: juejin.im/post/5e6caa…
Android WorkManager的使用: juejin.im/post/5e635e…