自從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…