GreenDao在Android项目中的实践总结

Posted Danny_姜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GreenDao在Android项目中的实践总结相关的知识,希望对你有一定的参考价值。

文章目录:

1 GreenDao 基本使用

2 GreenDao 多表之间的关联

3 GreenDao 保存List 类型数据

4 GreenDao 版本升级

基本使用

1 引入GreenDao

在project的build.gradle中引入GreenDao插件

buildscript 
    repositories 
        mavenCentral()
    
    dependencies 
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
    

然后在app的build.gradle中添加依赖

implementation 'org.greenrobot:greendao:3.2.2'

2 配置GreenDao

同样是在app的build.gradle中,添加如下配置

apply plugin: 'org.greenrobot.greendao'
greendao 
    schemaVersion 8
    daoPackage 'your_package.greendao.gen'
    targetGenDir 'src/main/java'

解释说明:

  • schemaVersion    指定数据库schema版本号,数据库的迁移等操作会用到

  • daoPackage     指定数据库dao的包名,默认是和Entity所在的包

  • targetGenDir    表示生成数据库包的目标路径

3 建立数据库实体类

@Entity  
public class User 
    @Id  
    private Long id;
    @Property(nameInDb = "USERNAME")
    private String username;
    @Property(nameInDb = "NICKNAME")
    private String nickname;

解释说明:

  • @Entity 表示这个实体类一会会在数据库中生成对应的 数据库表

  • @Id 表示该字段是id

  • @Property 则表示该属性将作为表的一个字段,其中nameInDb看名字就知道这个属性在数据库中对应的字段名称(列)

GreenDao每遍历到一个Entity注解时,都会为之创建一个相应的表格table,上述User的表格格式如下图所示:

当实体类创建成功之后, 使用如下命令编译整个项目:

./gradlew clean greendao

GreenDao会根据此实体类,自动生成XXXDao类,并保存在build.gradle中配置的daoPackage路径下,结果如下图所示:

图中红框处,GreenDao会默认生成DaoMaster和DaoSession两个类文件,通过这两个类来操作项目中创建的各个 数据库表 。

此外,为了方便数据库的操作,GreenDao默认还为Entity中的属性Properties设置了setter和getter方法,比如经过编译之后,Use.java中多了几个set和get方法,如下:

@Entity
public class User 
    @Id
    private Long id;
    @Property(nameInDb = "USERNAME")
    private String username;
    @Property(nameInDb = "NICKNAME")
    private String nickname;
    @Generated(hash = 523935516)
    public User(Long id, String username, String nickname) 
        this.id = id;
        this.username = username;
        this.nickname = nickname;
    
    @Generated(hash = 586692638)
    public User() 
    
    public Long getId() 
        return this.id;
    
    public void setId(Long id) 
        this.id = id;
    
    public String getUsername() 
        return this.username;
    
    public void setUsername(String username) 
        this.username = username;
    
    public String getNickname() 
        return this.nickname;
    
    public void setNickname(String nickname) 
        this.nickname = nickname;
    

4 数据库初始化

通过DevOpenHelper类对数据库进行初始化操作,DevOpenHelper有点类似于android SDK中自带的SQLiteOpenHelper。

// 首先获取一个DevOpenHelper对象
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "db_demo.db");

// 通过Helper类获取DaoMaster类
DaoMaster daoMaster = new DaoMaster(helper.getWritableDb());

// 通过DaoMaster获取DaoSession类,此类是操作数据库的关键
DaoSesson daoSession = daoMaster.newSession();

在构建DevOpenHelper时,需要指定创建的数据库名称。比如上述代码中,我创建了一个名为 db_demo.db 的数据库。

5 操作数据库

首先通过DaoSession获取响应的XXXDao对象,比如我之前创建的Entity实体类是User.java,编译之后GreenDao会自动生成UserDao.java类,因此我们需要通过DaoSession获取UserDao对象,并进行数据库增删改查操作,如下:

// 获取 UserDao 对象 -> 也就是 user 表格的引用
UserDao userDao = daoSession.getUserDao();

// 向 user 表格中插入数据
User user = new User();
user.setUsername("Danny");
user.setNickname("星哥");
userDao.insert(user);

执行上述代码,然后在 data/data/packageName目录下多了一个databases目录,在databases目录中有一个 db_demo.db 的数据库文件:

generic_x86:/data/data/com.danny.greendaopractise/databases # ls
db_demo.db db_demo.db-journal

通过sqlite3 命令可以连接此数据库,并查看内部表格中的数据:

generic_x86:/data/data/com.danny.greendaopractise/databases # sqlite3 db_demo.db

sqlite> select * from USER;
1|Danny|星哥
sqlite>

可以看出,成功向USER表格中创建了1条记录。除此之外,在代码中也可以通过以下方式查询表格中的内容:

List<User> users = userDao.queryBuilder().list();

GreenDao保存List类型数据

1 GreenDao默认不支持List插入

实际项目中,Entity实体类中可能会包含List类型的数据。比如在User中添加如下地址addresses字段:

其它代码不变,重新执行之前的代码,会发现代码如法经过编译,报错日志如下:

说明GreenDao默认是不支持以List的格式向数据库中插入数据的,在GreenDao自动生成的UserDao中有如下代码:

可以看出,GreenDao会将Entity类中的ID以及相关属性(Properties)设置到SQLiteStatement中,最终通过SQLiteStatement执行sql语句。

但是SQLiteStatement只能bind基本类型和String类型数据,如下所示:

2 将List<String>数据进行转化

如果要解决List数据插入问题,可以转换一下思路:遍历List数据,然后将所有的String对象都append到一个StringBuilder中,最终将StringBuild转化为String类型然后保存在数据库中即可。
事实上,GreenDao已经为我们考虑到了这种情况,因此才有了 PropertyConverter 这个接口。

在PropertyConverter接口中,有两个需要实现的抽象方法:

我们只需要实现此接口,并实现这两个抽象方法即可。具体如下:

需要传入泛型,分别是需要进行转换的List数据类型,以及最终被转化的目标数据类型。比如上述代码中,我们需要将User中的Listaddresses转化为String类型。

定义好StringConverter之后,接下来需要通过注解将StringConverter指定到需要进行转换的字段中,比如User.java 中的 addresses 字段:

通过注解 @Convert 指定addresses字段的转化工具类。

此时可以成功编译项目,再次查看UserDao中的bindValue方法,发现有如下改变:

如红框中所示,GreenDao解析@Convert注解时,会使用指定的Converter将List数据转化为String类型,并绑定到SQLiteStatement中进行数据库操作。

3 验证结果

使用如下代码,再次向数据库 db_demo.db 中插入一条数据

执行完之后,再次查看数据库中内容如下:

注意:执行之前,需要将之前的APK卸载,因为之前的数据库结构中并不存在addresses列,会造成程序崩溃。

实际开发中,对于比较复杂的List集合,可以考虑使用Gson来执行String和Bean之间的切换。

GreenDao多表之间关联

但是在实际开发中经常会遇到List的泛型并不是String类型的,而是另外一种自定义的Entity类型。比如新建一个Order.java 代表用户的某一个订单详情:

然后在User类中添加一个订单的集合,如下所示:

这种情况就需要将Order也定义为一个表格,并将它与User表格建立关联。具体如下:

然后在User中建立一对多的关系,如下:

红框中的 @ToMany 表示一个User可以对应订单Order表格中的多条记录,这与显示情况也是一致的,我们平时在购物平台上买东西,或者外卖平台上点外卖都可以多次下单,但是多有订单都指向同一个用户。这就是 "一对多" 的关系。

编译之后,可以看到在User中又多了对Order集合的操作

上面的操作是GreenDao自动生成的对Order集合的访问和操作,可以看出只包含了查找和重置所有订单的操作。

但是实际情况中,用户可以对某一个订单进行多次修改,因此后续需要程序开发人员在User中添加多种对订单的处理以及优化。

GreenDao 版本升级

上文中说过如果数据库的结构有改变,需要将之前的APK下载并重新安装。否则会因为数据库无法查找到字段而导致程序崩溃。但是在实际情况中,确实有需要做数据库升级的情况发生。比如后端数据结构一开始没有设计好,当生存环境已经有用户安装了APK时,后续就需要通过数据库升级来更新数据库的结构。

比如进行User表格的升级

GreenDao为我们提供了数据库升级的入口是在DaoMaster.OpenHelper 中。OpenHelper实际是继承自Android SDK中的DatabaseOpenHelper,当build.gradle中的GreenDao schemaVersion发送改变时(升级),会触发onUpgrade方法,进行数据库升级操作。

通常情况下,在onUpgrade方法中,我们需要做数据迁移工作。主要是将数据库现有表格的数据迁移到新的表格中,主要包含以下几步:

  1. 创建临时表,复制原来的数据库到临时表中

  2. 复制原来的数据库到临时表中

  3. 数据迁移:将临时表中的数据复制到新表中,最后将临时表删除

1 创建临时表

红框中为构建建表Sql语句,最后通过db.execSQL来执行此语句建临时表。

2 删除之前的原表并建立新表

删表和建表的操作很简单,只需要执行XXXDao的相应方法即可。以UserDao为例:

3 数据迁移

这一步比较关键,主要分2步完成

  • 将临时表中的数据复制到新表中

  • 删除临时表

完整代码如下:

解释说明:

  • 图中1处将临时表中的数据插入到新建表格中

  • 图中2处构建删表语句,并执行删除临时表

注意:

  • 在实际项目中,不一定每次数据库版本升级都需要做数据迁移的操作。毕竟这是一个比较耗时耗力也容易出错的操作。因此需要根据版本号来判读当前设备中的数据库是否需要做迁移。

  • 即使是需要做迁移,也并不是每一个表格都需要做迁移操作。比如上面的案例中只需要将User表格中的数据做迁移即可,最大程度的减少数据库表格的重建操作。

往期精选

Android源码系列

1 阿里3轮面试都问了RecyclerView

2 RecyclerView.ItemAnimator实现动画效果

3 RecyclerView.ItemAnimator源码解析

JVM深入理解系列

1 Java 线程池实践出真知

2 不要让你的Java对象"逃逸"了!

3 漫画Java线程池的工作机制

如果你喜欢本文

长按二维码关注

以上是关于GreenDao在Android项目中的实践总结的主要内容,如果未能解决你的问题,请参考以下文章

android greendao3.0 多表关联关系讲解(转)

Android GreenDao 在组件化项目中的一个问题 - 2018年7月5日21:15:14

Android笔记之greenDao3.0学习总结

有greenDAO线程安全最佳实践吗?

Android ORM对象关系映射之GreenDAO建立多表关联

Android Sqlite框架 GreenDao的源码分析笔记