Kotlin实战---使用Room封装本地数据层

2,595 阅读3分钟

没有Kotlin基础的小伙伴先进这里→ Koltin基础文章

Kotlin网络模型的实现→ Kotlin网络模型的实现

kotlin实战---MVP模式实现登录,实现Base层封装→ kotlin实战---MVP模式实现登录,实现Base层封装

1、为什么使用Room

Room 是一个 SQLite 对象映射库。它可用来避免样板代码,还可以轻松地将 SQLite 表数据转换为 Java 对象。Room 提供 SQLite 语句的编译时检查,并且可以返回 RxJava、Flowable 和 LiveData 可观察对象,使用ROOM可以让你更简单,更流畅的操作数据库,使用简单通过注解的方式就能对数据库进行增删改查,Google工程师帮你封装了访问SqlLite的代码,使你的代码性能更高

2、数据库的封装

先来一个图,理清思路再看代码

在这里插入图片描述

2.1、LocalRoomRequestManager

接口层实现,类似于网络模块里的API,将操作SqlLite的接口写到这里边

/***
 * 数据库获取标准接口,数据库读取
 * 只为 LocalRoomRequestManager 服务
 * DB 数据
 */
interface IDatabaseRequest {
    fun insertStudents(vararg students: Student)

    fun updateStudents(vararg students: Student)

    fun deleteStudents(vararg students: Student)

    fun deleteAllStudent()

    fun queryAllStudent() : List<Student> ?

    // TODO 可扩展 ...
}

/**
 * 为了扩展,这样写(在仓库里面的)
 * 本地获取标准接口(在仓库里面) 也就是本地的数据读取(包括本地xml数据,等)
 * 只为 LocalRoomRequestManager 服务
 *
 * xml 数据  本地数据
 */
interface ILocalRequest {
}

LocalRoomRequestManager类的实现,初始化的通过dataBase层获取dao,然后通过dao层进行增删改查

class LocalRoomRequestManager :ILocalRequest,IDatabaseRequest{
    var studentDao:StudentDao?=null
    //相当于Java代码的构造代码块
    init{
        val  studentDatabase=StudentDatabase.getDataBase()
        studentDao=studentDatabase?.getStudentDao()
    }
    companion object{
        var INSTANCE: LocalRoomRequestManager? = null

        fun getInstance() : LocalRoomRequestManager {
            if (INSTANCE == null) {
                synchronized(LocalRoomRequestManager::class) {
                    if (INSTANCE == null) {
                        INSTANCE = LocalRoomRequestManager()
                    }
                }
            }
            return INSTANCE!!
        }
    }
    override fun updateStudents(vararg students: Student) {
        studentDao?.updateStudents(*students)
    }

    override fun deleteStudents(vararg students: Student) {
       studentDao?.deleteStudent(*students)
    }

    override fun deleteAllStudent() {
        studentDao?.deleteAllStudent()
    }

    override fun queryAllStudent(): List<Student>? {
        return  studentDao?.queryAllStudents()
    }

    override fun insertStudents(vararg students: Student) {
        studentDao?.insertStudents(*students)
    }

}

2.2、Room操作

真正用来操作数据库的代码

初始化数据库

@Database(entities = [Student::class],version = 1)
abstract  class StudentDatabase: RoomDatabase() {
    abstract fun getStudentDao():StudentDao

    companion object{
        private  var INSTANCE:StudentDatabase?=null
        //Application 调用
        fun getDatabase(context: Context):StudentDatabase?{
                if(INSTANCE==null){
                    INSTANCE=Room.databaseBuilder(context,StudentDatabase::class.java,"student_database.db")
                        .allowMainThreadQueries()//允许在主线程查询
                        .build()
                }
            return INSTANCE
        }
        //使用者调用
        fun getDataBase():StudentDatabase?= INSTANCE
    }

}

在Application里去初始化database

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        // 初始化
        StudentDatabase.getDatabase(this)
    }

}

Room.databaseBuilde 就是实例化的DataBase的实现类 实现类里的代码: 在这里插入图片描述 这些都是框架生成的代码,省去了我们许多的样板代码 Dao层和Entity实现

@Dao
interface StudentDao {
    /***
     * 可变参数,插入数据
     */
    @Insert
    fun insertStudents(vararg students:Student)
    //更新数据
    @Update
    fun updateStudents(vararg  students:Student)

    //根据条件删除
    @Delete
    fun deleteStudent(vararg students:Student)
    //删除全部
    @Query("delete from student")
    fun  deleteAllStudent()
    //查询全部
    @Query("SELECT * FROM student ORDER BY ID DESC")
    fun queryAllStudents():List<Student>
	
}

@Entity
class Student(){
    @PrimaryKey(autoGenerate = true)//设置为主键,自动增长
    var id:Int=0
    @ColumnInfo(name="name")//别名 数据库中的名字如果不设置,默认是属性名称
    lateinit var name:String
    @ColumnInfo(name ="phoneNumber")
    lateinit  var phoneNumber:String
    //次构造
    constructor(name:String,phoneNumber:String): this(){
        this.name=name
        this.phoneNumber=phoneNumber
    }
}

框架生成的代码,大家可以自己去看一下,里面自动添加了事务,也加了锁,非常的nice 写完这些再去用MVP把LocalRoomRequestManager和Model层连起来,MVP上一篇贴的很详细了,这次的就不贴了 Kotlin版的适配器写法

class CollectAdapter :RecyclerView.Adapter<CollectAdapter.MyViewHolder>() {
    // 接收 数据库的数据
    var allStudents: List<Student> = ArrayList()
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val layoutInflater: LayoutInflater = LayoutInflater.from(parent.context)
        val itemView: View = layoutInflater.inflate(R.layout.item_collect_list, parent, false)
        return MyViewHolder(itemView)
    }

    override fun getItemCount(): Int =allStudents.size

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val student: Student = allStudents[position]
        holder.tvID.text = "${position + 1}"
        holder.tvName.text = student.name
        holder.tvPhoneNumber.text = "${student.phoneNumber}"
    }

    inner  class MyViewHolder(itemView: View):RecyclerView.ViewHolder(itemView){
        var tvID: TextView = itemView.findViewById(R.id.tv_id)
        var tvName: TextView = itemView.findViewById(R.id.tv_name)
        var tvPhoneNumber: TextView = itemView.findViewById(R.id.tv_phoneNumber)
    }

}

最终的效果

在这里插入图片描述

3、总结

需要注意的点在可变参数的传递过程中,不能将参数直接丢给方法得加一个* LocalRoomRequestManager.getInstance().insertStudents(*students) 体验用Kotlin开发项目的感觉,感觉比Java好用很多,还是很nice的,作为官方直推的语言还是挺值得学习的,