美文网首页Android
Android Jetpack之Room

Android Jetpack之Room

作者: MakerGaoGao | 来源:发表于2020-10-22 13:58 被阅读0次

    Room简介

    前言
    本篇中数据库调试工具使用debug-db,没接触过的可以看这里介绍
    

    https://blog.csdn.net/jinjin10086/article/details/103919983

    Room综述
    Room是Google Jetpack组件中的一员,是一种数据库的ORM框架,该库 在SQLite 的基础上提供了一个抽象层,让用户能够在充分利用 SQLite
    的强大功能的同时,获享更强健的数据库访问机制。
    
    Room相关的类
    注解相关
    1. @Entity注解:标识数据库映射关系的类,可以指定表名等,不指定的话默认表=名和类名一致,索引等信息。
    2. @PrimaryKey注解:指定主键,可设置自动增长等属性。
    3. @ColumnInfo注解:指定列信息,如列名等信息。
    4. @Ignore注解:标识忽略此属性,不对应生成数据库字段。
    5. @Dao注解:标识Dao层注解,编译时候会生成该接口或抽象类的实现。
    6. @Insert注解:标识该抽象方法为插入数据库,入参为Entity注解标注的类对象。
    7. @Query注解:标识该抽象方法为查询的方法(表面),需传入sql语句,其实sql语句可以实现增删改查的操作,也就是说可以实现常用全部操作。
    8. @Delete注解:标注该方法为删除的方法,入参为Entity注解标注的类对象。
    9. @Update注解:标注该方法为更新的方法,入参为Entity注解标注的类对象。
    10. @Database注解:标注该类为数据库操作类,一般为单例对象,入参entities为对应映射的kclass对象集合,verson处理数据库升级相关,通过此类可以拿到相关数据库操作的dao对象,进行相关的数据库操作。
    类相关
    1. RoomDatabase.java类:抽象类,处理数据库初始化,及dao对象的生成相关操作,目前操作只需要接触到这个类即可。
    2. Room.java类:类,内部采用Builder模式,用于生成具体的RoomDatabase的子类对象

    Room使用

    简单使用
    1. 依赖引入,如下:
         def room_version = “2.2.3”
        implementation "androidx.room:room-runtime:$room_version”
        kapt  "androidx.room:room-compiler:$room_version”
    
    1. ORM映射类创建,如下
        @Entity
        class PersonBean constructor(){
        
            constructor(name:String,age:Int):this(){
                this.name = name
                this.age = age
            }
        
            @PrimaryKey(autoGenerate = true)
            var id:Int? = null
            var name:String? = null
            var age:Int? = null
        
            @Ignore
            var sex:Int?=null
        
            override fun toString(): String {
                return "PersonBean(id=$id, name=$name, age=$age, sex=$sex)”
            }
        }
    
    1. Dao创建(对应增删改查四个方法)
        @Dao
        abstract class PersonDao {
        
            @Insert
            abstract fun insert(person: PersonBean)
        
            @Delete
            abstract fun delete(person: PersonBean)
        
            @Update
            abstract fun update(person: PersonBean)
        
            @Query("SELECT * FROM PersonBean”)
            abstract fun getPersonList():MutableList<PersonBean>
        
        }
    
    1. RoomDatabase子类创建,持有dao的引用,代码如下:
        @Database(entities = [PersonBean::class], version = 1)
        abstract class PersonRoomDatabase : RoomDatabase() {
        
            abstract fun personDao(): PersonDao
        
            companion object {
        
                @Volatile
                private var instance: PersonRoomDatabase? = null
        
                fun getPersonRoomDatabase(context:Context):PersonRoomDatabase{
                    if (null == instance){
                        synchronized(PersonRoomDatabase::class){
                            if (null == instance){
                                instance = Room.databaseBuilder(context.applicationContext,PersonRoomDatabase::class.java,"db_test").allowMainThreadQueries().build()
                            }
                        }
                    }
                    return instance!!
                }
        
            }
        
        }
    
    
    1. 调用,插入,调用如下:
        class TestActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_test_room)
            roomTest()
        }
    
        private fun roomTest() {
            val personDao = PersonRoomDatabase.getPersonRoomDatabase(this).personDao()
            val person = PersonBean("张大爷”,80)
            personDao.insert(person)
            Log.d(Common.TAG,"插入数据:$person”)
            val person1 = PersonBean("小张”,8)
            personDao.insert(person1)
            Log.d(Common.TAG,"插入数据:$person1”)
        }
    
    }
    

    运行日志:


    日志1

    查询数据库数据如下,显然已经插入成功


    数据1
    数据库名称对应RoomDatabase子类中指定的数据库名称,表明对应映射对象的类名,数据和日志一直,插入了两条数据
    1. 调用,删除,调用如下(这里只需传入id即可,因为删除的时候只用到id):
           val personBean = PersonBean()
            personBean.id = 1
            personDao.delete(personBean)
    

    查询数据库如下,显然已经删除成功


    数据2

    7.调用,更新,调用如下:

         val personBean = PersonBean("小张来了”,23)
            personBean.id = 2
            personDao.update(personBean)
    

    查询数据如下,显然已经更新成功


    数据3
    1. 调用,查询,如下:
          var personList: MutableList<PersonBean> = personDao.getPersonList()
            Log.d(Common.TAG,"共有${personList.size}个人”)
            personList.forEach {
                Log.d(Common.TAG,it.toString())
            }
    

    日志如下:


    日志2

    查询数据如下,和日志一致:


    数据4
    扩展使用
    @Query实现增删改

    和之前的增删改效果一致,代码如下:

        @Query("insert into PersonBean values (:id,:name,:age)”)
        fun insertQuery(id:Int?,name:String?,age:Int?)
    
        @Query("delete from PersonBean where id = :id”)
        fun deleteQuery(id:Int?)
    
        @Query("update PersonBean set name = :name , age = :age where id= :id”)
        fun updateQuery(id:Int?,name:String?,age:Int?)
    

    至于为什么没有使用person作为参数实现这个过程,在@Query的注释中已经说得很清楚了,只支持名字匹配识别


    注释1
    多参数插入、删除、更新操作
    插入代码如下(更新和删除类似):
    
        //dao
        @Insert
        fun insert(vararg person: PersonBean)
        //调用
         val person = PersonBean("张大爷", 80)
         val person1 = PersonBean("张大妈", 79)
         personDao.insert(person,person1)
         Log.d(Common.TAG, "插入数据:$person”)
         Log.d(Common.TAG, "插入数据:$person1”)
    
         var personList: MutableList<PersonBean> = personDao.getPersonList()
         Log.d(Common.TAG, "共有${personList.size}个人”)
         personList.forEach {
             Log.d(Common.TAG, it.toString())
         }    
    

    日志如下:


    日志3

    查询数据如下,和日志一致:


    数据5
    条件查询

    基本数据如下:


    数据

    查询Dao代码如下:

        @Query("select * from PersonBean where id= :id”)
        fun findById(id:Int?): MutableList<PersonBean>
    
        @Query("select * from PersonBean where age > :age”)
        fun findByAge(age:Int?): MutableList<PersonBean>
    
        @Query("select * from PersonBean where name like :name”)
        fun findByNameRule(name: String?): MutableList<PersonBean>
    
    

    1、findById方法id 传入3 ,结果如下:


    结果5

    2、findByAge方法 age传入16,结果如下:


    结果4
    3、findByNameRule方法
    name传入”张%”

    结果如下:


    结果1
    name传入”%张”
    结果2
    name传入"%张%”
    结果如下:
    结果3
    Room升级
    场景:
    1、增删表、增删字段
    步骤:
    1、改变版本号,在RoomDatabase的子类,如下改变version即可:
    @Database(entities = [PersonBean::class,Student::class], version = 2)
    2、如果是增加表,则相应的增加、减少entities数组的内容
    3、增加Migration,代码如下:
    
        Room.databaseBuilder(context.applicationContext,PersonRoomDatabase::class.java,”db_test”)
                                .addMigrations(object: Migration(1,2){
                                    override fun migrate(database: SupportSQLiteDatabase) {
                                        //此处为增删表、增删字段的sql书写处
                                        database.execSQL("CREATE TABLE IF NOT EXISTS `Student` (“ +
                                                "`id` INTEGER PRIMARY KEY AUTOINCREMENT,” +
                                                "`name` TEXT,” +
                                                "`age` INTEGER “ +
                                                ");”)
                                    }
                                })
                                .allowMainThreadQueries().build()
    
    其实增加表的时候Sql可以在此处找到,目录如下
    
    目录

    内容如下:


    内容

    删除的语句也能找到,如下:

    升级过程可以实现串式升级,即现在安装1版本,目标4版本,添加的迁移器是Migration(1,2),Migration(2,3),Migration(3,4),直接
    升级是可以成功的,没有问题,不需要添加Migration(1,4),Migration(2,4)等迁移器。
    
    关于Room使用,暂时先到此处,不做过多深入
    
    实现过程
    本来想分析一下创建表到数据操作的实现过程,限于篇幅与时间,后续再补上吧
    

    注意

    1、写Bean的时候一定要注意按照规范写 不然容易出现错误如下,没有具体报错的地方,其实是在编译阶段生成代码的时候报错了:


    错误1

    kotlin代码如下:

        @Entity(tableName = “tb_person”)
        class Person constructor(){
    
            constructor(name:String,age:Int):this(){
                this.name = name
                this.age = age
            }
        
            @PrimaryKey(autoGenerate = true)
            var id:Int? = null
            var name:String? = null
            var age:Int? = null
        
            override fun toString(): String {
                return "Person(id=$id, name=$name, age=$age)”
            }
        
        }
    

    2、select的结果是列表,要注意,不写返回值编译时不能通过的。
    3、数据库升级之后,再安装低版本会报错,不能覆盖安装,需要卸载之后重新安装,不然会报错如下:

    报错
    提示高版本到低版本的合并操作没有添加合并器,记住:
    卸载重新安装,卸载重新安装,卸载重新安装

    源码

    源码链接:源码

    总结

    1、关于Jetpack Room的介绍先到此处,后续可能会继续深入。
    
    2、自勉,实践出真知,blog记录自己成长,也能帮助一些需要该方面知识的人,不能没有经过验证的结论直接网上帖,那样难免会坑自己,
    也可能坑别人,就像上述的Room数据库升级操作 ,串式升级验证过,卸载直接安装高版本也验证过,验证通过的,当然如果因为一些特殊因素
    (如环境等可能会导致问题),那就再做讨论验证。
    
    3、Room总的用起来总的感觉良好:
        
        只需要在dao接口写方法声明就可以,通过PersonRoomDatabase拿到dao对象可以实现增删改查操作
        
        插入、更新、删除都很简单,注解操作就能实现,当然你要写sql也没人拦着,支持多参数操作也比较方便。
        
        查询操作是需要些sql的,参数支持名称识别,上述说过,总体也是很方便的
        
        在数据库升级的时候感觉稍显麻烦,需要自己添加迁移操作,需要些sqk语句(如增删表、增删字段等),之前用litepal是不需要写这些的,
        只需要更改版本号即可。
    
    4、注意中写到的注意点都是我在使用时候踩到的坑记录下来,避免以后再踩,也给后来者一点提示,能少踩点坑。

    相关文章

      网友评论

        本文标题:Android Jetpack之Room

        本文链接:https://www.haomeiwen.com/subject/psgumktx.html