安卓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");
        }
    };
目录
相关文章
|
3月前
|
XML API Android开发
码农之重学安卓:利用androidx.preference 快速创建一、二级设置菜单(demo)
本文介绍了如何使用androidx.preference库快速创建具有一级和二级菜单的Android设置界面的步骤和示例代码。
118 1
码农之重学安卓:利用androidx.preference 快速创建一、二级设置菜单(demo)
|
3月前
|
物联网 区块链 vr&ar
未来已来:探索区块链、物联网与虚拟现实技术的融合与应用安卓与iOS开发中的跨平台框架选择
【8月更文挑战第30天】在科技的巨轮下,新技术不断涌现,引领着社会进步。本文将聚焦于当前最前沿的技术——区块链、物联网和虚拟现实,探讨它们各自的发展趋势及其在未来可能的应用场景。我们将从这些技术的基本定义出发,逐步深入到它们的相互作用和集成应用,最后展望它们如何共同塑造一个全新的数字生态系统。
|
13天前
|
算法 JavaScript Android开发
|
22天前
|
Java 程序员 API
Android|集成 slf4j + logback 作为日志框架
做个简单改造,统一 Android APP 和 Java 后端项目打印日志的体验。
86 1
|
2月前
|
Java Maven 开发工具
第一个安卓项目 | 中国象棋demo学习
本文是作者关于其第一个安卓项目——中国象棋demo的学习记录,展示了demo的运行结果、爬坑记录以及参考资料,包括解决Android Studio和maven相关问题的方法。
第一个安卓项目 | 中国象棋demo学习
|
1月前
|
测试技术 数据库 Android开发
深入解析Android架构组件——Jetpack的使用与实践
本文旨在探讨谷歌推出的Android架构组件——Jetpack,在现代Android开发中的应用。Jetpack作为一系列库和工具的集合,旨在帮助开发者更轻松地编写出健壮、可维护且性能优异的应用。通过详细解析各个组件如Lifecycle、ViewModel、LiveData等,我们将了解其原理和使用场景,并结合实例展示如何在实际项目中应用这些组件,提升开发效率和应用质量。
44 6
|
2月前
|
前端开发 Java 数据库
💡Android开发者必看!掌握这5大框架,轻松打造爆款应用不是梦!🏆
在Android开发领域,框架犹如指路明灯,助力开发者加速应用开发并提升品质。本文将介绍五大必备框架:Retrofit简化网络请求,Room优化数据库访问,MVVM架构提高代码可维护性,Dagger 2管理依赖注入,Jetpack Compose革新UI开发。掌握这些框架,助你在竞争激烈的市场中脱颖而出,打造爆款应用。
344 3
|
2月前
|
编译器 Android开发 开发者
带你了解Android Jetpack库中的依赖注入框架:Hilt
本文介绍了Hilt,这是Google为Android开发的依赖注入框架,基于Dagger构建,旨在简化依赖注入过程。Hilt通过自动化的组件和注解减少了DI的样板代码,提高了应用的可测试性和可维护性。文章详细讲解了Hilt的主要概念、基本用法及原理,帮助开发者更好地理解和应用Hilt。
77 8
|
2月前
|
安全 Java Android开发
探索安卓应用开发的新趋势:Kotlin和Jetpack Compose
在安卓应用开发领域,随着技术的不断进步,新的编程语言和框架层出不穷。Kotlin作为一种现代的编程语言,因其简洁性和高效性正逐渐取代Java成为安卓开发的首选语言。同时,Jetpack Compose作为一个新的UI工具包,提供了一种声明式的UI设计方法,使得界面编写更加直观和灵活。本文将深入探讨Kotlin和Jetpack Compose的特点、优势以及如何结合使用它们来构建现代化的安卓应用。
62 4
|
3月前
|
SQL JavaScript 前端开发
vue中使用分页组件、将从数据库中查询出来的数据分页展示(前后端分离SpringBoot+Vue)
这篇文章详细介绍了如何在Vue.js中使用分页组件展示从数据库查询出来的数据,包括前端Vue页面的表格和分页组件代码,以及后端SpringBoot的控制层和SQL查询语句。
vue中使用分页组件、将从数据库中查询出来的数据分页展示(前后端分离SpringBoot+Vue)