今天学习android的数据库和协程
ROOM#
ROOM类似于JPA,能够定义DAO层使用预置的方法进行数据的操作。ROOM主要包含下面三个组件:
-
Database数据库类: 用于保存数据库并作为应用持久性数据底层连接的主要访问点。其实我感觉Database的类就是提供了Dao层的实例。
-
Entity实体类:用于表示应用的数据库中的表。
-
Dao类:提供您的应用可用于查询、更新、插入和删除数据库中的数据的方法。类似于Spring中的Dao层,定义了操作数据库的方法。
Entity#
实体类就是我们常见的实体类,使用的注解也和JPA类似
-
@Entity(tableName = “users”):该注解说明该类是一个实体类,并且关联了users的表
-
@PrimaryKey:用于字段上,说明该字段是主键
-
@ColumnInfo(name = “last_name”):用于字段上,绑定实体类中的属性和表中的字段
1
2
3
4
5
6
|
@Entity(tableName = "users")
data class User (
@PrimaryKey val id: Int,
@ColumnInfo(name = "first_name") val firstName: String?,
@ColumnInfo(name = "last_name") val lastName: String?
)
|
Dao#
在Dao类中定义方法来操作数据库。下面是一个简单样例:
1
2
3
4
5
6
7
8
9
10
11
|
@Dao
interface UserDao {
@Insert
fun insertAll(vararg users: User)
@Delete
fun delete(user: User)
@Query("SELECT * FROM user")
fun getAll(): List<User>
}
|
可以看到提供了Insert和Delete的注解,不需要编码sql语句即可完成数据库操作,和JPA类似。
-
@Insert 和 @Update: insert和update就是插入和更新,参数为实体类
-
@Delete: 以实体类为参数删除实体,实体类中必须包含主键
-
@Query: query就直接可以写原生的sql去查询或者去进行数据库的操作
Database#
关于Database类有点不太理解,已经有了Dao层去完成数据库操作,只需要在ViewModel中去引入Dao层然后操作即可,为什么还有要Database呢?下面是官方的样例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {
abstract val sleepDatabaseDao: SleepDatabaseDao
companion object {
@Volatile
private var INSTANCE: SleepDatabase? = null
fun getInstance(context: Context): SleepDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}// Song and Album are classes annotated with @Entity.
@Database(version = 1, entities = {Song.class, Album.class})
abstract class MusicDatabase : RoomDatabase {
// SongDao is a class annotated with @Dao.
abstract fun getSongDao(): SongDao
// AlbumDao is a class annotated with @Dao.
abstract fun getArtistDao(): ArtistDao
// SongAlbumDao is a class annotated with @Dao.
abstract fun getSongAlbumDao(): SongAlbumDao
}
|
可以看到使用了@Database的注解,包含了版本号,以及实体类,这里的实体类比较好理解,是下面引用的Dao类的实体类。那么版本号呢?
版本号用户数据库表结构的更新,如果数据库表结构变更了,则需要变更版本号,然后设置Database的实例创建增加fallbackToDestructiveMigration配置就可以了。
但是这样做会有缺点,所有的数表都会被删掉,所以需要使用迁移功能。
迁移功能在更新版本号的同事还需要重写migrate方法然后将表结构更改的语句加上即可,如下.
1
2
3
4
5
6
7
8
|
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
//此处对于数据库中的所有更新都需要写下面的代码
database.execSQL("ALTER TABLE users "
+ " ADD COLUMN last_update INTEGER");
}
};
|
加完之后database的实例加上.addMigrations(MIGRATION_1_2)就完成了。
一般java使用多线程来处理业务量比较大的操作,那么在android+kotlin里面使用协程来操作。
如果一个应用必须等待某项任务完成后才能继续,那么系统可能会阻止其正常执行。例如,读取大文件或执行冗长的数据库调用就是可能会阻止或“阻塞”整个应用执行的任务。这样不仅会降低应用对用户的响应能力,而且也不能高效地利用硬件。执行长时间运行的任务而不阻塞主线程的一种模式是使用回调。这是一种有用的模式,但它有一些缺点。有关这些概念的介绍,请参阅多线程和回调入门指南。
有关于协程的知识,官方解释的很清楚:
在 Kotlin 中,使用协程来顺畅且高效地处理长时间运行的任务,而不是回调。Kotlin 协程使您能够将基于回调的代码转换为顺序代码。顺序编写的代码通常更易于阅读和维护。与回调不同,协程可以安全地使用有价值的语言功能,如异常。最重要的是,协程具有更高程度的可维护性和灵活性。最后,协程和回调执行相同的功能:它们都能够处理应用中可能长时间运行的异步任务。
简而言之,对于需要回调的方法来说,使用协程可以不等回调,顺序执行。
有关协程的操作可以看官方文档:
https://kotlinlang.org/docs/coroutines-guide.html
协程在android中的使用#
如room中的操作,对于数据库的操作完全可以使用协程后台操作。所以上述的简单样例可以改成这样:
1
2
3
4
5
6
7
8
9
10
11
|
@Dao
interface UserDao {
@Insert
suspend fun insertAll(vararg users: User)
@Delete
suspend delete(user: User)
@Query("SELECT * FROM user")
suspend getAll(): List<User>
}
|
更多的协程的知识,请看系列博文:
https://juejin.cn/post/6953441828100112392