本文目的在于,针对room原生api中有一些不方便的地方,基于注解与RxJava,kotlin的强大lambda表达式进行包装节省大量开发工作。

谷歌发布了ROOM数据库,与其他常见数据库api的区别是,基于注解与sql,不需要像其他库一样去记数据库内置的DAO的各种操作api函数,数据库迁移功能很强大而且逻辑清晰,便于维护。官方支持RxJava,对于查询结果可以很方便的实现异步订阅。

Room提供给我们的是一个基础的有无限可能的库,也许对于新手程序员来说,不如greendao等库用起来足够傻瓜式(只需要记住增删改查的api,不需要自己去写dao的sql语句),但是谷歌的库都有一个特点,就是基于你的能力,可以有无限的扩展可能(databinding库也是类似,新手觉得没有便捷多少,但是如果你自己积累,编写了很多自定义xml属性,和自己改造包装通用的工具方法,databinding甚至可以让给你在xml中一行属性完成listView的adapter从创建,填充数据一条龙服务,这点稍后会把我的基于databinding的包装心得写一篇文章,抛砖引玉,启发大家想出天马行空的使用方式)。关于数据库的使用不做过于详细的讲解,我这里只对于从0开始组建room数据库实践过程中的心得,如何利用。

关于ROOM的痛点:

1.对比与其他的开源数据库,在创建dao的时候,需要手动写增删该查,如果表很多,也有不小的工作量。

2.不进行包装,原生使用方式基于Dao对象操作,对于增删改查都要写大量的rxJava的订阅监听以及线程的模版代码,这些都可以通过技术手段简化,避免。

github地址:

GitHub – chrism1981/fastRoomDatabase: Room Database for Android, with kotlin. 基于room数据库的包装,快速开发,一行代码增删改查

一.下面我们来看一下原生的Room使用过程(归结为:Entity,Dao,DataBase三大对象):

1.对数据对象进行@entity注解处理,转化为Entity类:比较简单,class上标记@Entity,对于主键变量,标记@PrimaryKey

2.根据Entity对象,创建对应对DAO类,通过注解的方式,将SQL(不用害怕敲sql,用room库的话,在敲sql的时候也是有代码提示的,不会像写纯string一样出现笔误等情况。)语句注册给对应对操作方法:

  1. 创建自己的DataBase类(继承RoomDatabase),声明你之前创建的dao的操作方法

4.以查询方法为例子,api的实际调用:获取数据库实例,获取dao实例,操作dao的方法。

二.本文的包装思路与实际操作预览:

下面是我的包装方法:首先解决不必要重复写的增删等方法。然后已一个DataBaseHelper类来包装,操作数据库,将rxjava的订阅过程包装起来,并且引入带参数的查询。

主要解决问题就是免去大量的模版代码,rxjava代码,线程操作,数据库操作,都由

最终预览下,我们想调用一个SearchRecordDao来查询,获取到一个结果list,显示到一个textview上,最终的全部代码如下:

一行代码完成查询过程,不用关心数据库如何创建,dao如何创建,异步线程操作等等都不需要在开发时候重复去操作了。

三.大致结构与流程:

结构:

流程:

四. 主要代码讲解:

1.Dao类注解的标记:

其中@IsQuery :无参数查询所有数据;@IsQueryWithKey 带一个参数的查询,@IsDeleteAll :删除全部。 以上这些方法的Sql其实都可以copy,只是表名不同。

2.DBHelper 中的工作:

当这个Dao被创建标记完成以后,我们马上就可以通过操作 DBHelper来进行操作这个表的查询,比如要调用通过 id查询结果(getSearchRecordById()方法):传一个key,Dao的class,成功获取结果后的回调函数(lambda表达式)

这个调用对应都就是我们刚才在SearchRecordDao.class里的getResearchRecordById()方法,它是通过注解 @ IsQueryWithKey被识别,当我们调用时候传的“1270030”就是id参数。

首先,通过DBHelper找到dao,然后调用dao的对应带参数查询方法,数据库的关闭也在这里进行。queryListWithKey方法如下:

其中的success 和fail 类型为 (t:List)->(Unit)这个代表一个lambda表达式,

对于lambda不熟悉的同学,我简答讲解下怎么理解这个东西。

当这个表达式success(t)被调用的时候,这个方法的设计者会把他查询到的结果(一个list)通过invoke这个表达式的方式传递给你,以便于你的表达式在编写的时候,就可以针对这个查询结果出来以后,如何进行下一步工作给出方案。其中suceess(t) 就是调用lambda表达式,其实它和调用函数是一样的。如果熟悉c,c++的同学,可以发现,它和函数指针的概念很像。

对于用java的同学,可以这样对照lambda和匿名内部类:

{  list-> int size = list.size() }  可以这样理解 ,假设又一个Success接口包含一个参数为list的方法,

success = new Success(){  

@override

public void recall(List list){

int size = list.size();

} }

其实任何一个lambda表达式,都可以用一个接口来代替。而相对于接口,lambda可以说,是去掉了定义接口类,创建匿名对象这一过程,可以用一个式子来完成全部工作。

3.Dao中的代码:

dao中的具体实现方法,都在BaseDao中,由父类实现了 insert,delete ,update等方法。子类中主要就是声明query方法,并用注解中写好Sql语句。

BaseDao:

这个方法虽然是在BaseDao中,但我们但子类Dao中会继承这个方法,当它在运行时候,反射获取的所有method是当前子类的所有方法,这样我们在写BaseDao的时候,就可以实现找到将来任意一个子类中代表了有参查询@IsQueryWithKey的方法,并且调用这个方法,在父类里就预先写好RxJava的订阅。

最后的结果就是使用时候直接调用DbHepler.queryWithKey(..),然后Dbhelper会自己去找到BaseDao的query方法,BaseDao在找到当前子类Dao的query方法。完成查询。

总结:当然这只是一个思路,满足大部分app中数据库简单应用,比如一些复杂的sql语句查询,肯定会有,但不会是每一条查询都是复杂的。我们简化包装,如果可以覆盖一半以上的应用场景,那它就是值得的。

后期还有很多可以扩展的地方,比如带参数的查询,可以扩展到多个参数,同一个Dao中,可能需要多个含单参数查询的方法,比如按name查询,按age查询,我们同样可以扩展实现,比如在@IsQueryWithKey注解中接受参数,注解可以接受基础数据类型和枚举。 这样一来,对于2个不同的单参数查询方法,可以用 @IsQueryWithKey(name) 和@IsQueryWithKey(age)来标记不同方法,在项目中也可以维护一个常量表,用于代表这些查询参数,这样在调用Dbhelper来查询的时候,通过传入对于参数,就可以区分当前想要查询的条件是什么。

最后附上地址

github地址:

GitHub – chrism1981/fastRoomDatabase: Room Database for Android, with kotlin. 基于room数据库的包装,快速开发,一行代码增删改查

文章来源于互联网:Room数据库包装-通过kotlin包装一行代码增删改查

发表评论