安卓Jetpack组件Room数据库框架的使用(附Demo)

简介: 安卓Jetpack组件Room数据库框架的使用(附Demo)

简单介绍

最开始学习安卓的时候,会继承自SQLiteOpenHelper来编写自己的数据库;之后一些优秀的三方开源数据库框架出现了,我用过的有郭神的LitePal、greenrobot的greenDao(EventBus也是他编写的);为了帮助支持各位开发者,google推出了自己的数据库框架Room。

官方定义

官方介绍:The Room persistence library provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.

翻译过来就是,Room persistence库在SQLite上提供了一个抽象层,允许流畅的数据库访问,同时利用SQLite的全部功能。

样例效果

写的demo很简单,大家凑合看:

20191114110927261.gif

使用方式

首先我们需要在项目的build.gradlle文件添加google的maven仓库(as高版本中自动添加的就有)

allprojects {
    repositories {
        jcenter()
        google()
    }
}

接着在主module的build.gradle文件添加依赖

implementation 'android.arch.persistence.room:runtime:1.1.1'
    annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'
    implementation 'android.arch.persistence.room:testing:1.1.1'

接下来建立一个实体类吧,Room中的表无需像原生一样sql语句来创建,类似于greendao,都i是通过实体类映射的方式来创建。里面有几个注解,感觉和greendao差不多。

  1、 @Entity(tableName="表名称")

         此注解放在实体类的类名上面,可以设置表的名称、主键、外键等信息,源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Entity {
    String tableName() default "";
    Index[] indices() default {};
    boolean inheritSuperIndices() default false;
    String[] primaryKeys() default {};
    ForeignKey[] foreignKeys() default {};
}

   2、@PrimaryKey(autoGenerate = true)


         此注解放在主键变量上,并定义自增


   3、@ColumnInfo(name = "字段名称")


         此注解放在普通变量上,字段映射具体的数据表字段名


   4、@Ignore


         这个注解需要好好说一下,可放在方法和变量上。Room定义必须有一个无参的构造方法,所以说如果你想有别的构造方法的话需要在别的构造方法上添加上此注解。如果说你实体类中的字段不是表中的字段,这时也需要忽略下,需要在变量上添加此注解。


好了,介绍完这些让我们来看一下实体类最终样子(get和set方法必须要生成):

/**
 * 设备类(外部数据库)
 *
 * @author jiang zhu on 2019/10/25
 */
//entity声明定义,并且指定了映射数据表明
@Entity(tableName = "equip_type")
public class EquipType {
    //设置主键,并且定义自增增
    @PrimaryKey(autoGenerate = true)
    private int id;
    //字段映射具体的数据表字段名
    @ColumnInfo(name = "name")
    private String name;
    //字段映射具体的数据表字段名
    @ColumnInfo(name = "component")
    private int component;
    //字段映射具体的数据表字段名
    @ColumnInfo(name = "code")
    private String code;
    //字段映射具体的数据表字段名
    @ColumnInfo(name = "default_line_type")
    private int defaultLineType;
    //字段映射具体的数据表字段名
    @ColumnInfo(name = "icon")
    private String icon;
    //字段映射具体的数据表字段名
    @ColumnInfo(name = "remark")
    private String remark;
    //必须指定一个构造方法,room框架需要。并且只能指定一个
    //,如果有其他构造方法,则其他的构造方法必须添加@Ignore注解
    public EquipType() {
    }
    //其他构造方法要添加@Ignore注解
    @Ignore
    public EquipType(int id, String name, int component, String code, int defaultLineType, String icon, String remark) {
        this.id = id;
        this.name = name;
        this.component = component;
        this.code = code;
        this.defaultLineType = defaultLineType;
        this.icon = icon;
        this.remark = remark;
    }
    @Override
    public String toString() {
        return "EquipType{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", component=" + component +
                ", code='" + code + '\'' +
                ", defaultLineType=" + defaultLineType +
                ", icon='" + icon + '\'' +
                ", remark='" + remark + '\'' +
                '}';
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getComponent() {
        return component;
    }
    public void setComponent(int component) {
        this.component = component;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public int getDefaultLineType() {
        return defaultLineType;
    }
    public void setDefaultLineType(int defaultLineType) {
        this.defaultLineType = defaultLineType;
    }
    public String getIcon() {
        return icon;
    }
    public void setIcon(String icon) {
        this.icon = icon;
    }
    public String getRemark() {
        return remark;
    }
    public void setRemark(String remark) {
        this.remark = remark;
    }
}

增删改查

数据库最重要的就是增删改查,这个Room和greendao不太一样:room需要自己来写dao(数据操作 增删改查)。那就一个一个来吧:


1.增加 @Insert(onConflict = OnConflictStrategy.REPLACE)

OnConflictStrategy.REPLACE表如已有数据,就覆盖掉。数据的判断通过主键进行匹配,也就是id,非整个EquipType对象。增加分为两种,一种是增加一条、另外一种是增加多条数据,

//返回Long数据表示,插入条目的主键值(id)
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    Long insert(EquipType equipType);
    //返回List<Long>数据表示被插入数据的主键id列表
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    List<Long> insertAll(List<EquipType> equipTypeList);


2.删除 @Delete

删除就比较简单了,直接添加注解返回int处理成功条数即可。

@Delete
    int delete(EquipType equipType);
    @Delete
    int deleteAll(List<EquipType> equipTypeList);


3.修改 @Update

修改也一样,需要传入修改完的实体类,其中必须要有主键(通过主键来进行修改)

@Update()
    int update(EquipType equipType);
    @Update()
    int updateAll(EquipType... equipTypes);


4.查询 @Query("SELECT * FROM equip_type")

查询灵活性就很大了,可以直接里面写sql语句。很赞的是:Room可以直接判断你写的表名是否存在,还和参数值一一对应。

@Query("SELECT * FROM equip_type")
    List<EquipType> getAll();
    //参数cid和注解中的cid相对应  注解中的equip_type和id和实体类中的相对应
    @Query("SELECT * FROM equip_type WHERE id = :cid")
    LiveData<EquipType> findByUid(int cid);

数据库创建

表的实体类在上面已经写完,接下来创建一下数据库。需要继承自RoomDatabase。实现如下:


/**
 * @author jiang zhu on 2019/11/12
 */
//注解指定了database的表映射实体数据以及版本等信息
@Database(entities = {EquipType.class}, version = 1)
public abstract class ZhuDatabase extends RoomDatabase {
    //RoomDatabase提供直接访问底层数据库实现,我们通过定义抽象方法返回具体Dao
    //然后进行数据库增删该查的实现。
    public abstract EquipTypeDao equipTypeDao();
}

需要在创建的类的上面添加@Database注解,其中的entities是一个数组,可以添加多个类,相应的在下面可以创建多个抽象方法(多个表的情况下),以便使用。


接下来需要创建数据库了:

//得到ZhuDatabase 对象
 private var db : ZhuDatabase? = null
 //得到Dao对象
 private var equipTypeDao : EquipTypeDao? = null
private fun initData() {
        db = Room.databaseBuilder(
            applicationContext,
            ZhuDatabase::class.java, "room-database"
        )
            //添加数据库变动迁移
            //.addMigrations(AppDatabase.MIGRATION_1_2)
            //默认设置为不可在主线程执行,需要重新开启线程
            // .allowMainThreadQueries()
            .build()
        equipTypeDao = db!!.equipTypeDao()
    }

可在里面设置数据库的迁移(下面会说到)和是否可在主线程操作,不建议在主线程操作,建议放在子线程(数据库操作比较耗时)。

实现功能

首先创建布局,代码太简单就不在这里放代码了,布局样式如下,


20191114130621472.png


然后创建按钮的点击事件:

override fun onClick(v: View) {
        when (v.id) {
            R.id.mainBtnAddOne -> {
                insertOne()
            }
            R.id.mainBtnAddSome -> {
                insertSome()
            }
            R.id.mainBtnDeleteOne -> {
                deleteOne()
            }
            R.id.mainBtnDeleteSome -> {
                deleteSome()
            }
            R.id.mainBtnUpdateOne -> {
                updateOne()
            }
            R.id.mainBtnUpdateSome -> {
                updateSome()
            }
            R.id.mainBtnQueryOne -> {
                queryOne()
            }
            R.id.mainBtnQuerySome -> {
                querySome()
            }
        }
    }

由于代码比较多,在这里只展示比较重要的代码。

下面是增加一条数据的代码,这里用到了线程池,需要的可以访问我的github,地址会在文章末尾贴出。

//增加一条
    private fun insertOne() = threadPool.execute {
        val result = equipTypeDao!!.insert(
            EquipType(
                1,
                "朱江",
                2,
                "你猜",
                3,
                "http://192.168.8.18:81/zentao/file-read-4910.png",
                "呵呵"
            )
        )
        runOnUiThread {
            if (result > 0)
                ToastUtils.showShort("新增成功")
        }
    }

增加多条数据代码类似,只是插入时放了一个集合。下面是查询一条数据的代码,

//查询一条
    private fun queryOne() = threadPool.execute{
        val equipType =  equipTypeDao!!.findByUid(1)
        runOnUiThread {
            equipType.observe(this, Observer {
                mainTvResult.text =it.toString()
            })
        }
    }

数据库升级

这里已经完成了数据库的基本操作,上面也提到了数据库的变动迁移,在ZhuDatabase中定义方法进行操作即可,下面是代码示例:

//数据库变动添加Migration
    public static final Migration MIGRATION_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(SupportSQLiteDatabase database) {
            //数据库的具体变动
            //类型是integer,不为空,默认值是0
            database.execSQL("ALTER TABLE equip_type "
                    + " ADD COLUMN number INTEGER NOT NULL DEFAULT 0");
        }
    };
目录
相关文章
|
9月前
|
人工智能 数据挖掘 API
基于neo4j数据库和dify大模型框架的rag模型搭建——后续补充
基于neo4j数据库和dify大模型框架的rag模型搭建——后续补充
924 21
基于neo4j数据库和dify大模型框架的rag模型搭建——后续补充
|
9月前
|
Java 数据库 Docker
基于neo4j数据库和dify大模型框架的rag模型搭建
基于neo4j数据库和dify大模型框架的rag模型搭建
2650 35
|
7月前
|
SQL XML Java
配置Spring框架以连接SQL Server数据库
最后,需要集成Spring配置到应用中,这通常在 `main`方法或者Spring Boot的应用配置类中通过加载XML配置或使用注解来实现。
594 0
|
8月前
|
安全 Java Android开发
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
386 0
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
|
9月前
|
数据库 Android开发 开发者
Android常用的room增删改查语句(外部数据库)
本文分享了将一个原生数据库驱动的单词APP重构为使用Room库的过程及遇到的问题,重点解决了Room中增删改查的常用语句实现。文章通过具体示例(以“forget”表为例),详细展示了如何定义实体类、Dao接口、Database类以及Repository和ViewModel的设计与实现。同时,提供了插入、删除、更新和查询数据的代码示例,包括模糊查询、分页加载等功能。此外,针对外部数据库导入问题,作者建议可通过公众号“计蒙不吃鱼”获取更多支持。此内容适合有一定Room基础的开发者深入学习。
294 0
Android常用的room增删改查语句(外部数据库)
|
前端开发 Java 编译器
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
375 36
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
|
10月前
|
SQL 数据库连接 数据库
在C++的QT框架中实现SQLite数据库的连接与操作
以上就是在C++的QT框架中实现SQLite数据库的连接与操作的基本步骤。这些步骤包括创建数据库连接、执行SQL命令、处理查询结果和关闭数据库连接。在实际使用中,你可能需要根据具体的需求来修改这些代码。
651 14
|
存储 缓存 Java
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
1735 3
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
|
算法 JavaScript Android开发
|
11月前
|
Oracle 关系型数据库 Java

热门文章

最新文章