1 在项目的build 依赖
def lifecycle_version = "2.2.0" def room_version = "2.3.0" implementation'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7' implementation'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0' implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" implementation("androidx.room:room-runtime:$room_version") annotationProcessor "androidx.room:room-compiler:$room_version"
注:如果项目是使用Kotlin语言来开发的,在添加room-compiler的时候使用kapt关键字,java语言开发的就使用annotationProcessor关键。否则会导致访问出错。
2.理解room的概念
- Entity:实体类,对应的是数据库的一张表结构。需要使用注解 @Entity 标记。
- Dao:包含访问一系列访问数据库的方法。需要使用注解 @Dao 标记。
- Database:数据库持有者,作为与应用持久化相关数据的底层连接的主要接入点。需要使用注解 @Database 标记。 使用@Database注解需满足以下条件: 定义的类必须是一个继承于RoomDatabase的抽象类。 在注解中需要定义与数据库相关联的实体类列表。 包含一个没有参数的抽象方法并且返回一个带有注解的 @Dao。
3.创建bean
@Entity(tableName = "user_pro") data class UserProEntity( @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "_id") val _id: Long, @ColumnInfo(name = "name") val name: String, @ColumnInfo(name = "age") val age: String, @ColumnInfo(name = "phone") val phone: String, @Ignore val isCode: Boolean )
在@Entity注解中我们传入了一个参数 tableName用来指定表的名称。@PrimaryKey注解用来标注表的主键,并且使用autoGenerate = true 来指定了主键自增长。@ColumnInfo注解用来标注表对应的列的信息比如表名、默认值等等。@Ignore 注解顾名思义就是忽略这个字段,使用了这个注解的字段将不会在数据库中生成对应的列信息。也可以使用@Entity注解中的 ignoredColumns 参数来指定,效果是一样的。
4.对数据库进行操作
@Dao interface UserProDao { @Query("SELECT * FROM user_pro") fun getAllUserPro(): LiveData<List<UserProEntity>> @Query("SELECT count(*) FROM user_pro") fun count(): Long @Query("Delete from user_pro") fun clear() @Query("SELECT * FROM user_pro WHERE name=:name") fun getUser(name: String): LiveData<UserProEntity> @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(userProEntity: UserProEntity) @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertAll(userProEntity: List<UserProEntity>) @Query("update user_pro set name=:name,age=:age where _id=:id") fun insertId(name: String, age: String, id: Long) @Query("delete from user_pro where _id=:id") fun deleteId(id: Long) }
Dao类是一个 interface,其中定义了一系列的操作数据库的方法。通常我们操作数据库无非就是增删改查。Room也为我们的提供了相关的注解,有@Insert、@Delete、@Update 和 @Query。
@Query
我们先来看下 @Query 查询注解,它的参数时String类型,我们直接写SQL语句进行执行,而且编译的时候可以进行语法检查。比如我们根据ID查询某个用户的信息:
@Query("SELECT * FROM user_pro") fun getAllUserPro(): LiveData<List<UserProEntity>>
@Insert
注解标注就可以:
@Insert(onConflict = OnConflictStrategy.REPLACE) fun addUser(user: User)
我们看到直接中有个参数onConflict,表示的是当插入的数据已经存在时候的处理逻辑,有三种操作逻辑:REPLACE、ABORT和IGNORE。如果不指定则默认为ABORT终止插入数据。这里我们将其指定为REPLACE替换原有数据。
@Delete
如果需要删除表的数据则使用 @Delete注解:
@Delete fun deleteUserByUser(user: User)
使用主键来查找要删除的实体。
@Update
如果需要修改某一条数据则使用 @Update注解,和@Delete一样也是根据主键来查找要删除的实体。
@Update fun updateUserByUser(user: User)
上面说的 @Query 查询接受的参数是一个字符串,所以像删除或者更新我们也可以使用 @Query 注解来使用SQL语句来直接执行。比如根据userid来查询某个用户或者根据userid更新某个用户的姓名:
@Query("delete from user where userId = :id ") fun deleteUserById(id:Long) @Query("update user set userName = :updateName where userID = :id") fun update(id: Long, updateName: String)
5.创建数据库并升级数据库
@Database(entities = [UserProEntity::class], version = 1, exportSchema = false)
abstract class TestDatabase : RoomDatabase() {
abstract fun userProDao(): UserProDao
companion object {
private const val TAG = "TestDatabase"
private var instance: TestDatabase? = null
private val DATABASE_NAME: String = "my_db"
fun getInstance(context: Context): TestDatabase {
return instance ?: synchronized(this) {
instance ?: buildDatabase(context).also { instance = it }
}
}
private fun buildDatabase(context: Context): TestDatabase {
return Room.databaseBuilder(context, TestDatabase::class.java, DATABASE_NAME)
.addMigrations(MIGRATION_1_2)
.addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
Log.e(TAG, "onCreate: ")
}
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
Log.e(TAG, "onOpen: ")
}
})
.build()
}
private val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"CREATE TABLE IF NOT EXISTS USER_PRO" +
"('_id' LONG PRIMARY KEY AUTOINCREMENT NOT NULL," +
"'name' TEXT" +
"'age' TEXT" +
"'phone'TEXT" +
")"
)
}
}
}
}
6.使用Repository思想
class UserProRepository {
companion object {
@Volatile
private var instance: UserProRepository? = null
fun getInstance() =
instance ?: synchronized(this) {
instance ?: UserProRepository().also { instance = it }
}
}
private val userProDao: UserProDao =
TestDatabase.getInstance(Utils.getApp().applicationContext).userProDao()
suspend fun initUser() {
val userProEntity: MutableList<UserProEntity> = ArrayList()
var s_1 = UserProEntity(1, "小学", "11", "123456789",true)
var s_2 = UserProEntity(2, "小学", "12", "123456789",true)
var s_3 = UserProEntity(3, "中学", "13", "123456789",true)
var s_6 = UserProEntity(6, "中学", "14", "123456789",true)
var s_5 = UserProEntity(5, "大学", "19", "123456789",true)
var s_4 = UserProEntity(4, "大学", "22", "123456789",true)
userProEntity.add(s_1)
userProEntity.add(s_2)
userProEntity.add(s_3)
userProEntity.add(s_6)
userProEntity.add(s_5)
userProEntity.add(s_4)
val userProEntityList: MutableList<UserProEntity> = ArrayList()
userProEntityList.clear()
if (userProDao.count() != 0L) {
userProEntityList.addAll(userProEntity)
}
userProDao.insertAll(userProEntityList)
}
//获取全部信息
fun getUser() = userProDao.getAllUserPro()
//保存某人信息
fun saveUser(userProEntity: UserProEntity) = userProDao.insert(userProEntity)
/**
* 保存全部信息
*/
suspend fun saveUserList(list: List<UserProEntity>) = userProDao.insertAll(list)
/**
* 删除全部
*/
suspend fun deleteUser() = userProDao.clear()
/**
* 获取数量
*/
fun getNumber()=userProDao.count()
}
7.结合VIewModel
class UserProfileViewModel(private val userProRepository: UserProRepository) : ViewModel() {
private val myString: MutableLiveData<List<UserProEntity>> = MutableLiveData()
lateinit var mutableList: LiveData<List<UserProEntity>>
fun getUserPro(): MutableLiveData<List<UserProEntity>> {
viewModelScope.launch {
myString.postValue(userProRepository.getUser().value)
// mutableList=userProRepository.getUser()
}
return myString
}
fun initUser() {
viewModelScope.launch {
userProRepository.initUser()
}
}
fun saveUserPro(userProEntity: UserProEntity) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
userProRepository.saveUser(userProEntity)
}
}
}
fun saveAllUser(list: List<UserProEntity>) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
userProRepository.saveUserList(list)
}
}
}
private fun loadNumberShowNumber() {
usertNumber!!.value = userProRepository.getNumber()
}
private var usertNumber: MutableLiveData<Long>? = null
fun getUserShowNumber(): LiveData<Long> {
if (usertNumber == null) {
usertNumber = MutableLiveData()
loadNumberShowNumber()
}
return usertNumber!!
}
}
8.设置模式
class SelfViewModelFactory(private var proRepository: UserProRepository): NewInstanceFactory() {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (ViewModel::class.java.isAssignableFrom(modelClass)) {
return try {
modelClass.getConstructor(UserProRepository::class.java).newInstance(proRepository)
} catch (e: NoSuchMethodException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: IllegalAccessException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: InstantiationException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: InvocationTargetException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
}
}
return super.create(modelClass)
}
}
最后调用
class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity"
lateinit var viewModel: UserProfileViewModel
lateinit var userProRepository: UserProRepository;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this, SelfViewModelFactory(userProRepository)).get(
UserProfileViewModel::class.java
)
viewModel.initUser()
viewModel.getUserPro().observe(this, Observer {
Log.e(TAG, "onCreate: $it")
})
}
}