Android Jetpack架构组件-Room基本使用

作者: OneXzgj | 来源:发表于2020-03-31 18:49 被阅读0次

    一、简介

    Room有三个主要的组件:Database、Dao、Entity

    • 数据库(Database):你可以使用该组件创建数据库的持有者。该注解定义了实体列表,该类的内容定义了数据库中的DAO列表。这也是访问底层连接的主要入口点。注解类应该是抽象的并且扩展自RoomDatabase。在运行时,你可以通过调用Room.databaseBuilder()(理解为常规数据库的定义)或者Room.inMemoryDatabaseBuilder()(数据保存在内存中,即程序关掉,数据丢失)获取实例。

    • 实体(Entity):这个组件代表了持有数据库表记录的类。对每种实体来说,创建了一个数据库表来持有所有项。你必须通过Database中的entities数组来引用实体类。实体的每个成员变量都被持久化在数据库中,除非你注解其为@Ignore

    • 数据访问对象(DAO):这个组件代表了作为DAO的类或者接口。DAO是Room的主要组件,负责定义访问数据库的方法。被注解@Database的类必须包含一个无参数的抽象方法并返回被@Dao注解的类型。当编译时生成代码时,Room会创建该类的实现。

    Database、Dao、Entities 和 app 的关系图如下所示:

    截屏2020-03-3114.55.04.png

    二、如何使用

    我们以简单示例来具体实现如上核心类:

    1.添加依赖

    添加相关room依赖包Room版本说明,读者可根据如上链接,获取最新版本及按需依赖即可

    2.定义Database类

    /**
     * des:Database
     * author:onexzgj
     */
    @Database(entities = [Cheese::class], version = 1)   //注释1
    abstract class CheeseDb : RoomDatabase() {
    
        abstract fun cheeseDao(): CheeseDao
    
        companion object {
            private var instance: CheeseDb? = null
    
            fun get(context: Context): CheeseDb {
                if (instance == null) {
                    //注释2
                    instance = Room.databaseBuilder(context, CheeseDb::class.java, "onexzgj")
                    //是否允许在主线程进行查询
                        .allowMainThreadQueries()
                        .addCallback(object : RoomDatabase.Callback() {
                            override fun onCreate(db: SupportSQLiteDatabase) {
                                super.onCreate(db)
                            }         
                        })
                        .build()
                }
                return instance!!
            }
    }
    
    • 在注释1处
      使用@Database注解,表示是数据库的入口类,参数entities是数组类型,需要将当前APP中的所有涉及到的数据库表类,都写入这个参数,version参数表示当前数据库的版本,其实还有一个参数为 exportSchema =true,默认为true,按照字面意思为导出数据库概要,即每次操作数据库的一个摘要信息,但是需要注意的事,如果手动设置为true时,需要在build.gradle中的指定导出文件的位置,如下所示:
      defaultConfig {
            ...
            javaCompileOptions{
                annotationProcessorOptions{
                    arguments=["room.schemaLocation":"$projectDir/schemas".toString()]
                }
            }
        }
    

    这个时候,等程序运行之后,就会在根目录生成schemas目录,并且产生一个json文件,如下所示:


    image.png
    • 在注释2处
      可以根据项目需要选择内存数据库,且还有如下回调方法,如下所示:
            //创建一个内存数据库
            //但是这种数据库的数据只存在于内存中,也就是进程被杀之后,数据随之丢失
            Room.inMemoryDatabaseBuilder(...)
                    //是否允许在主线程进行查询
                        .allowMainThreadQueries() 
                    //数据库创建和打开后的回调
                    .addCallback()
                    //设置查询的线程池,一般不需要设置
                    .setQueryExecutor()
                    .openHelperFactory()
                    //room的日志模式
                    .setJournalMode()
                    //数据库升级异常之后的回滚,默认重新进行创建
                    .fallbackToDestructiveMigration()
                    //数据库升级异常后根据指定版本进行回滚
                    .fallbackToDestructiveMigrationFrom()
                    // 数据库迁移升级时使用,后文会提到
                     .addMigrations(CacheDatabase.sMigration)
    

    3.定义Dao

    @Dao
    interface CheeseDao {
    
        @Query("select * from cheese order by name ")
        fun findAllCheese(): DataSource.Factory<Int, Cheese>    //注释1
    
        @Query("select * from cheese order by name ")
        fun getAllCheese(): List<Cheese>?      //注释2
    
        @Insert
        fun insert(cheeses: List<Cheese>)
    
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        fun insert(cheese: Cheese)
    
        @Delete
        fun delete(cheese: Cheese)
    }
    
    • 注释1处
      返回的数据类型为DataSource.Factory<Int,Cheese>,注释2处返回的数据类型为List<Cheese> 从这里可以看到Room数据库是原生支持Paging框架,如果不了解Paging的可以查看笔者之前的文章Paging框架

    • 注释2处
      返回的数据类型为 List<Cheese>? ,则可以直接返回List集合
      当然这里也可以搭配Rxjava2使用,返回对象为 Flowable<List<CheeseAndUser>> ,后续再介绍

    4、定义Entity

    @Entity
    data class Cheese(
        @PrimaryKey(autoGenerate = true) val id: Int, val name: String
    )
    

    通过@Entity注解标注的类,则表示这个类会映射到数据库中,默认表名为类名,
    通过@ PrimaryKey,标明主键,通过设置autoGenerate参数设置true,则表示主键会自增长

    5、代码中使用

            val allCheese = CheeseDb.get(this).cheeseDao().getAllCheese()
            Log.d("DATATA", allCheese?.get(0)?.name + ":" + allCheese?.size)
    

    运行结果如下所示:


    运行结果.png

    到这里相信对Room数据库有一个基本的了解,如果了解Orm或者GreenDao的同学,应该对上面的步骤或者创建不难理解,接下来介绍核心类的具体参数的含义及用法

    三、核心类属性讲解

    3.1 、@Entity注解包含的属性有:

    tableName:设置表名字,默认是类的名字。
    indices:设置索引,按需添加,会提高查询速度,增加更新和新增的操作时间
    inheritSuperIndices:父类的索引是否会自动被当前类继承,没用到过,暂不解释
    primaryKeys:设置主键,一般通过直接在主键字段上添加@PrimaryKey
    foreignKeys:设置外键。
    Ignore:设置不需要映射到数据库中的字段可以使用,则不会在表中出现该字段

    如下所示:

    @Entity(tableName = "table_cheese")
    data class Cheese(
        @PrimaryKey(autoGenerate = true) val id: Int, 
        
        @ColumnInfo(name = "testName")
        val name: String,
        @Ignore
        val temp:String
    )
    

    3.2、@Query注解是

    它是DAO类中使用的主要注释,允许对数据库执行读/写操作。@Query在编译的时候会验证准确性,所以如果查询出现问题在编译的时候就会报错,如字段拼写常规错误等。

    Room还会验证查询的返回值,如果返回对象中的字段名称与查询响应中的相应列名称不匹配的时候,Room会通过以下两种方式之一提醒您:
    如果只有一些字段名称匹配,它会发出警告。
    如果没有字段名称匹配,它会发生错误。

    @Query注解value参数:查询语句,根据需求,完成查询sql语句即可。

     @Query("select * from cheese  where name ==:name ")
     fun getCheese(name:String): List<Cheese>?
    

    四、结语

    到这里,Room的基本使用就差不多介绍完成了,那么在实际开发中,仅仅掌握基本使用,是远远不够的,如多表查询,一对一、一对多等关系的查询如何实现?配合Rxjava/LiveData/Paging的使用

    本文示例代码已上传至Jetpack_Component

    相关文章

      网友评论

        本文标题:Android Jetpack架构组件-Room基本使用

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