大家早上好,看到这个标题,相信很多喜欢LitePal朋友应该是一把鼻涕一把泪。两年多了,今天终于又升级了

是的,我看了一下时间,LitePal的上个版本还是2018年10月份发布的,之后就再也没有更新过。因为我接下来将主要的时间都放在了giffun这个项目上,忙完giffun紧接着又开始编写《第三行代码》,以至于完全没有时间和精力去维护LitePal。

期间有不少朋友咨询过我,是不是放弃维护LitePal了?莫名感到有点心酸,我欠这个项目的有点多了。

那么时隔两年之后的更新,LitePal又发生了什么变化呢?我们一起来看一看吧。

/   Close Issues   /

这两年时间里,我不光没有时间更新LitePal的功能,甚至连GitHub上的issues都无暇顾及,以至于积累了大量的issues。那么在开发新功能之前,首先要做的,肯定是解决这些issues。

我将所有的issues都浏览一遍之后,发现大体可以归为以下几类:

1. 用法的咨询。对于这类issue我基本都进行了回复,只是回复的有点太晚了,可能没能帮上你们的忙,这里非常抱歉。

2. 功能上的建议。这些年来许多朋友都在LitePal的功能性方面提供了不少建议,也让LitePal变得更加强大。不过关于功能建议方面的事情我待会还会再谈,这里暂时先跳过。

3. 系统类型的Bug。有些朋友使用LitePal时遇到了崩溃,就认为是LitePal的bug,但有的时候并非如此。比如CursorWindows这个bug被提了好几次,但其实这是系统底层的限制,CursorWindow缓存数据达到最大限制就会抛出异常。即使你不使用LitePal,用原生的SQLiteDatabase也会出现这个异常,所以这种问题我确实无法修复,大家只能在使用层面尽量减少这种一次性加载大量数据的场景。

4. LitePal的Bug。对于提出这类问题的朋友我非常感谢,这次确实又发现了几个LitePal内部的bug。比如特定情况下升级数据库会丢失数据、Date类型字段无法保存1970年以前的数据、findFirst()方法在某些时候查询速度会非常慢等等。这次在开发新版本之前,我将这些提出的bug全部都进行了修复,保证这是一个更加稳定的版本。

那么现在LitePal的GitHub中还剩下多少issue呢?给大家看一下:

没错,就只剩下一个了。并且这是一个新功能的建议,我确实计划在之后的版本中考虑加入这个功能,所以暂时将它保留了下来。

好了,现在issues都解决掉了,接下来终于可以对LitePal进行升级了。

/   合二为一   /

在之前的LitePal 3.0.0版本当中,我为了让它支持一些Kotlin中不错的语法特性,将原来的一个库变成了两个库,如下图所示:

是的,使用哪种编程语言就引入哪个库,我本来认为这是一件很好的事情,然而没过多久我就后悔了,这是一个非常错误的决定。

将库分成了Java和Kotlin两个版本之后,它们又会共同引入Core库来作为依赖,Core库是主业务逻辑实现的地方。那么当需要添加什么新功能的时候,我需要在Core库中进行具体的功能实现,然后在Java库中添加一个对外接口,在Kotlin库中添加一个对外接口,还要为Kotlin的专属语法再添加一个对外接口。本来只需要在一个地方维护的代码现在变成了要在四个地方维护,所有API的数量也变成了四倍,导致代码维护成本急剧增加。

这个问题是我必须要解决的,不然以后LitePal会变得越来越难维护。所以,在最新的LitePal 3.1.0版本当中,已经不再区分Java版和Kotlin版,而是统一合并成一个库。只需要声明以下依赖库地址,即可将LitePal升级到3.1.0版本,Java和Kotlin语言都可以使用:

dependencies {implementation 'org.litepal.guolindev:core:3.1.1'
}

合二为一之后,大量冗余的代码就都可以删除了,维护成本也骤降了许多。至于是如何实现的,这主要得感谢bintray-release这个开源库(https://github.com/novoda/bintray-release)。它在将开源项目打包成库发布到jcenter之前,会先解析当前项目的依赖情况,然后将项目所需要依赖哪些库一起声明到pom文件当中。比如LitePal 3.1.0版本的pom文件如下所示:

可以看到,这里在dependencies当中声明了LitePal是需要依赖Kotlin的一些运行时库的,如果你当前的项目中没有这些库(比如是使用Java开发的项目),那么Gradle会自动将这些依赖下载下来,以保证LitePal可以正常运行。

这样就不用再专门为Java和Kotlin提供两个版本的库了,而是一份代码同时兼容两种语言,皆大欢喜。

/   做减法   /

这里我想要回到刚才功能建议的话题。

LitePal从诞生一直到现在,其实都还算是一个比较小众的开源库。因为本身移动端数据库的需求就不是特别强,再加上LitePal也不是移动数据库框架中做得最出色的那个,所以不可能得到所有人的认可。

但是也有不少Android开发者,他们对LitePal特别喜爱,觉得这个库简单好用,可以省去编写好多代码。有一些热衷的朋友会向我提出很多建议,加入某某之类的功能,从而让这个库变得更加强大。

我特别感谢向我提出建议的这些朋友们,可以说在很大程度上,LitePal的版本迭代更新都是在你们的建议基础上进行的。

但是,迭代了这么多版本之后,我回过头来反思一下,是不是每一个建议都值得采纳呢?这是要打上问号的。

因为是一个小众开源库,建议本身可能就不太多,所以我很愿意听取,并在这些建议的基础上做加法。但是做了这么多年加法之后,我发现有些建议其实并不怎么合理,也不被大多数开发者所需要。加上这些功能之后,还会使得LitePal变得不稳定,或者是维护变得更加困难。

所以,这次我决定对LitePal做减法。

经过仔细思考之后,我决定分阶段移除以下三部分内容。

1. 二进制数据存储

这个功能是我非常不应该增加的一个功能,因为数据库本身就不适合存储二进制数据。为什么呢?二进制数据通常都会很大,一张高清图片可能就会占据几M的内存,将这种数据存放到数据库中是比较危险的,很可能会引发刚才提到的CursorWindows的错误导致程序崩溃,这就让LitePal变得不够稳定。

那么又有多少开发者会有向数据库中存储二进制数据的需求呢?这个真的很少,因为大部分人的做法都是将二进制数据以文件的形式存储到本地,然后在数据库中存储一条文件的路径就可以了。这种做法更加科学安全,也不会给数据库增加额外的压力。

因此,从LitePal 3.1.0版本开始,将不再支持存储和读取二进制数据功能(实体类中定义的byte数组字段将被忽略),此项变更立即生效,如果有用到这部分功能的朋友,请在升级之前完成修改。

2. 异步操作

数据库操作需要异步进行,这个是一种非常提倡的行为,因为操作数据库本身就是比较耗时的。

然而,数据库操作需要异步进行,就意味着数据库框架需要提供异步功能吗?我以前是这么认为的,所以我在LitePal中加了很多异步操作的接口,不过现在我意识到,我又做错了。

因为除了数据库操作之外,有很多其他耗时操作也需要异步进行。异步这个话题展开来讲可以讲很深,也有极多的API和开源库可以用来实现异步功能,比如Java线程池、RxJava、协程等等。所以LitePal其实并不应该承担这个职责,有很多更适合的框架会专门处理这个事情。举个例子,Google的Room就完全没有提供异步操作数据库接口,但是默认情况下Room还强制要求你必须在非主线程进行数据库操作,否则就会崩溃。

另外,LitePal的异步操作接口设计得也确实非常不好,导致后期维护成本很高。比如说查询数据有一个find接口,那么为了可以异步查询数据,我就又提供了一个findAsync接口。删除数据有一个delete接口,为了可以异步删除数据,我就又提供了一个deleteAsync接口。大家发现问题了没有?为了提供异步操作,我将API的数量翻倍了,再加上之前又将库分为了Java和Kotlin两个版本,API在翻倍的基础之上又翻了四倍,维护成本指数级增加。

所以,在异步操作方面,我准备继续做减法,LitePal不再额外承担异步处理工作,但是也不会像Room那样强制要求开发者必须在非主线程操作数据库。到底是在主线程还是非主线程操作数据库,全凭大家自由选择。如果你们的项目中已经使用了RxJava或协程等技术,异步处理相信对于你来说本身就是一件很轻松的事情,也完全用不着使用LitePal提供的异步操作接口。

考虑到老项目的兼容性,此项变更并不会立即生效,目前只是所有的异步接口都被标记为了废弃,但在下一个版本当中将会完全移除,所以也请大家不要再继续使用这些接口了。

3. 数据库存储位置

LitePal在1.6.0版本当中,引入了将数据库存储到外置SD卡的功能,主要是为了方便大家调试程序。然而这种行为是极其危险的一种行为,会大大影响应用程序的安全性,因为谁都可以随意地更改数据库中的数据。

这个功能到底该去该留,我也考虑了很久。一方面是觉得,像Room这种Google官方的数据库框架都没有提供将数据库存储到外置SD卡的功能,LitePal为什么要多做这件事情。另一方面又觉得,数据库难以调试这确实是一个开发者的痛点。

深思熟虑之后,我决定暂时继续保留这个功能,但是随着未来开发调试环境越来越发达(比如Android Studio 4.1中已经引入数据库调试功能了),我最终还是会移除这个功能。

/   saveAll接口   /

用过LitePal的朋友都知道,在LitePal当中向数据库存储一条数据是非常简单的,只需要调用如下代码即可:

Person person = new Person();
person.setXXX(...);
...
person.save();

save方法是LitePal提供的一个接口,它会解析当前对象中包含的数据、字段、关联关系等信息,然后将解析出来的数据存储到数据库表对应的列当中。

存储一条数据是上面这种写法,那么如果我要存储一个集合当中的数据应该怎么做呢?当然你可以这样写:

List<Person> personList = ...
for (Person person : personList) {person.save();
}

得到了一个集合之后,我们只需要循环遍历这个集合,调用每个Person对象的save方法就可以了。

但是刚才有提到,LitePal的save方法中会解析当前对象包含的数据、字段、关联关系等信息。你会发现除了数据是会变化的之外,像字段、关联关系这种信息每个对象都是相同的,所以每次循环都去解析一遍这些信息无疑会增加存储耗时。

为此LitePal提供了一个saveAll方法,专门用于存储集合类型的数据,比如实现上述同样的功能,也可以这样写:

List<Person> personList = ...
LitePal.saveAll(personList);

这两种写法实现的功能是一模一样的,但是saveAll方法只会将Person对象中的字段与关联关系解析一次,因此存储效率将会大幅提升。

然而,saveAll方法也有一个缺点,就是如果存储的集合当中,有部分数据存储成功了,部分数据存储失败了怎么办?要知道,saveAll方法并没有返回值。

为了处理这种情况,LitePal 3.1.0版本当中特意增加了saveAll方法的返回值。

saveAll方法会返回true和false两种返回值,true表示集合中的所有数据都存储到了数据库当中,false表示存储过程中发生了异常,没有任何数据存储到了数据库当中。是的,saveAll方法内部开启了事务,要么全部存储成功,要么全部存储失败,不会出现部分存储成功的情况,这样可以避免很多使用saveAll方法时产生的误解。

另外,在3.1.0版本当中,我还为Kotlin提供了saveAll方法的专属语法糖,如果你的项目使用的正是Kotlin语言的话,可以用如下写法来调用saveAll方法:

val personList: List<Person> = ...
personList.saveAll()

很明显,这种写法变得更加清爽了。

/   支持事务   /

LitePal内部的API在很早之前就支持了事务功能,因为要保证数据操作的原子性,不能出现部分成功部分失败的情况。

然而,LitePal之前却从来没有提供过对外的事务接口,但是广大开发者却实实在在会有事务方面的需求。

举个最常见的事务例子,你正在开发一个转账功能,需要先从一个账户中减去先一定的金额,然后向另一个账户中增加相同的金额。整套操作必须保证是原子性的,即要么同时成功,要么同时失败。如果部分成功的话,转账之后,账户的总金额就对不上了。

为此,LitePal 3.1.0版本当中终于加入了事务接口的支持,并且用法也十分简单,因为和SQLiteDatabase中提供的事务接口用法是几乎一致的。

当我们要进行一套数据库操作,并且要保证它们要么同时成功,要么同时失败,这个时候就可以这样写:

try {LitePal.beginTransaction();boolean result1 = // 数据库操作1boolean result2 = // 数据库操作2boolean result3 = // 数据库操作3if (result1 && result2 && result3) {LitePal.setTransactionSuccessful();}
} finally {LitePal.endTransaction();
}

可以看到,这里调用beginTransaction方法来开启事务,调用endTransaction方法来结束事务,中间所有的数据库操作都是在事务当中的。如果所有的操作都成功了,那么我们可以在结束事务之前调用一下setTransactionSuccessful方法,这样所有的操作就都生效了。否则的话,所有的操作都会被回滚,就好像什么都没发生过一样。

事务的用法就是这么简单,然而在Kotlin当中,事务的用法会更加简单,因为我又提供了一个Kotlin专属的事务API,写法如下:

LitePal.runInTransaction {val result1 = // 数据库操作1val result2 = // 数据库操作2val result3 = // 数据库操作3result1 && result2 && result3
}

我来简单解释一下,我们可以给runInTransaction方法传入一个Lambda表达式,表达式中的所有代码就都是在事务当中运行的了,这种语法特性是利用Kotlin的高阶函数功能实现的。关于高阶函数上次我在直播的时候介绍得很详细,《第三行代码》也对这部分内容做了非常全面的讲解。

而Lambda表示式的最后一行要求返回一个布尔值,用于标识是否所有数据库操作都成功了,只有返回true的时候事务中的数据库操作才会生效,返回false或者中途发生异常所有的操作都会被回滚。

/   我没学过LitePal怎么办?   /

以上就是关于LitePal 3.1.0版本更新的所有内容,不过本篇文章是写给已经有LitePal基础的人看的,帮助他们快速地升级到3.1.0版本。如果你之前并没有接触过LitePal,那么可以阅读我写的技术专栏《Android数据库高手秘籍》,里面有非常详尽的LitePal使用讲解。

专栏地址是:

https://blog.csdn.net/sinyu890807/category_9262963.html

LitePal开源库地址是:

https://github.com/LitePalFramework/LitePal

推荐阅读:

这本《第三行代码》,让大家久等了!

LitePal 3.0.0发布,一次不可思议的升级

我新开发了一个特别好用的开源库

欢迎关注我的公众号

学习技术或投稿

长按上图,识别图中二维码即可关注

时隔两年,LitePal终于又更新了!相关推荐

  1. 多多自走棋改动_多多自走棋:重大更新,一直被玩家念叨的两个地方终于改了...

    今天<多多自走棋>终于又更新啦!各位更新后进入游戏,是不是吓一跳啊,毕竟进入游戏第一眼就是看到糖果有好几千,领取赛季更新时的糖果也有好几千,在更新界面没看更新信息的玩家估计都乐开了花.毕竟 ...

  2. 鸿蒙开发者目前人数,苹果时隔两年公布大中华区开发者数据:440万,增长76%

    原标题:苹果时隔两年公布大中华区开发者数据:440万,增长76% 新京报贝壳财经讯(记者 许诺)5月31日,苹果时隔两年后公布了大中华区最新的开发者数据.数据显示,苹果大中华区目前已拥有超过440万注 ...

  3. xcode 可以打开xmind_XMind 推出的轻量化脑图工具,时隔两年迎来大版本更新:Lighten 2...

    我在写第一代 Lighten 的 介绍文章 时对它的定义是「回到脑图最开始的样子」,而上周 Lighten 带来了第二代大版本更新,这款思维导图工具在官网也获得了新的诠释: 全新的 Lighten,从 ...

  4. 魅族 系统更新服务器,魅族系统终于迎来更新,涉及虽少但有大变更,你准备好了吗?...

    原标题:魅族系统终于迎来更新,涉及虽少但有大变更,你准备好了吗? 距离魅族新品发布会已经过去了两天,相信各位魅友对于发布会上推出的 Flyme 8 印象深刻,虽然 Flyme 8 已经正式发布,但很多 ...

  5. 两个月后才更新一篇。。。。LIB和DLL的差别

    两个月后才更新一篇....LIB和DLL的差别  共同拥有两种库: 一种是LIB包括了函数所在的DLL文件和文件里函数位置的信息(入口).代码由执行时载入在进程空间中的DLL提供,称为动态链接库d ...

  6. 动森服务器维护时长,《动森》在两三年内都会不断更新内容 保证游戏体验

    原标题:<动森>在两三年内都会不断更新内容 保证游戏体验 各位岛民有认真打理自己的小岛吗?近日<集合啦!动物森友会>已经推出了最新免费更新,在体验地球日活动的同时,官方其实早就 ...

  7. 小米miui系统已停止服务器,小米两款机型停止 MIUI 更新,明天发布最终体验版固件...

    原标题:小米两款机型停止 MIUI 更新,明天发布最终体验版固件 11 月 21 日消息, MIUI 官方预告 MIUI 于 2018 年 11 月 22 日发布小米手机 5 .红米 Note 3 全 ...

  8. 中国时隔两年再次全面降息 专家称或刺激楼市回暖

    中国时隔两年再次全面降息 专家称或刺激楼市回暖 行业动态中新网李金磊2014-11-22 00:06 我要分享 2 中新网北京11月22日电(记者 李金磊)时隔两年之后,中国今日再次实施全面.非对称性 ...

  9. 小爱音响php接口,时隔两年,小爱音响终于更新了

    9 月 17 号上午 10:00,小爱音箱官博正式宣布小爱音箱推出全新版本,新款小爱音箱延续上代产品的名称,就叫做 小爱音箱,只不过新增了 小爱音箱 pro 版本. 小爱音箱主要更新:750mL 超大 ...

最新文章

  1. QC数据库恢复,解决SQL孤立用户问题
  2. Mysql索引基本概念及案例总结(含索引的使用注意事项)
  3. .NET Core 的过去、现在和未来
  4. 中缀转后缀表达式,带括号的后缀表达式综合计算器,Java栈数据结构实现
  5. python sum函数numpy_如何用numba加速python?
  6. C语言 va_start 宏 - C语言零基础入门教程
  7. 简单在于的acdsee 2012
  8. 手机安装linux发行版,最近发布新版本的Linux发行版汇总 - 2020-02-14
  9. 案例分析:你造吗?有个ORA-60死锁的解决方案
  10. python无缘无故不执行/跳过某个函数,无报错无警告
  11. python怎么输出浮点数_【数会小课堂】Python知识第二弹
  12. springmvc网页找不到404_eclipse新建WebProject访问主页404错误的解决
  13. 【Java定时任务调度工具】Timer
  14. android按钮对齐方式,表格行中三个按钮的对齐方式Android
  15. 扩展JavaScript数组(Array)添加删除元素方法
  16. php ://input 消息头 消息体,php curl_init curl 消息头和消息体
  17. 谷歌浏览器历史版本解决chrome浏览器安装不上的问题
  18. Arduino驱动MAX30102心率血氧传感器模块
  19. 基于百度短语音API的语音识别实现
  20. 我的低代码布道师之路

热门文章

  1. js开发的麻将对对碰游戏
  2. 设计网页页脚的15个超实用技巧
  3. HRMS(人力资源管理系统)-从单机应用到SaaS应用-架构分析(功能性、非功能性、关键约束)-上篇...
  4. Buuoj re [easyre|reverse1|reverse2|内涵的软件|新年快乐|xor]
  5. php 执行时间超时
  6. 基于视觉与板球系统的智能垃圾桶
  7. 从0到1入门STM32最小系统板(2-1)——绘制原理图之器件选型
  8. 第一封情书——祝老婆生日快乐
  9. 一个姓名按照笔画排序的页面
  10. python基础语法-绘制奖状