Android数据库高手秘籍(五)LitePal的存储操作

经过前面几篇文章的学习,我们体会到了LitePal来创建表、升级表、以及建立表关联所带来的便利。本篇咱们使用LitePal来进行表的CRUD操作。还没有看过前一篇文章的朋友建议先去参考 Android数据库高手秘籍(四)使用LitePal建立表关联

LitePal提供的CRUD操作的API还是颇为丰富的,一篇文章肯定是介绍不全的,因此这里我们仍然是分几篇文章进行讲解,本篇主要是介绍存储方面的API。

LitePal的项目地址是:https://github.com/LitePalFramework/LitePal

logo.png

传统的存储数据方式

Android专门提供了一种用于存储数据的简便方法,使得我们不用编写SQL语句就可以执行存储操作。下面来看一下SQLiteDatabase中的insert()方法:

public long insert(String table, String nullColumnHack, ContentValues values)

可以看到,insert方法接收三个参数,第一个参数是表名,第二个参数通常都用不到,直接传null,第三个参数则是一个封装了待存储数据的ContentValues对象。因此,比如说我们想往news表中插入一条新闻,就可以这样写:

SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("title", "这是一条新闻标题");
values.put("content", "这是一条新闻内容");
values.put("publishdate", System.currentTimeMillis());
long id = db.insert("news", null, values);

调用ContentValues的put()方法来添加待存储数据,put()方法接收两个参数,第一个参数是数据库表中对应的列名,第二个参数就是要存储的值,最后调用一下insert()方法,这条新闻就会插入到news表当中了,id代表插入的成功的第几条数据。

比起直接使用SQL语句,SQLiteDatabase中提供的insert()方法的确简单了很多。但insert()方法也并非是那么的完美,它还是有很多不方便的地方的,比如说没有考虑表关联的情况,我们需要手动对关联表的外键进行存储。再比如说,没有提供批量存储的功能,当我们有一个集合的数据需要存储时,需要通过循环来遍历这个集合,然后一次次地调用insert()方法来插入数据。

使用LitePal存储数据

LitePal中与存储相关的API其实并不多,但用法还是很丰富的,而且比起传统的insert()方法,使用LitePal来存储数据可以简单到让你惊叹的地步,那么今天我们就来完整地学习一下LitePal存储数据的所有用法。

在前面几篇文章中,我们在项目里已经建好了News、Comment、Man、Woman这几个实体类,通过这些实体类,LitePal就可以把相应的表自动创建出来。现在来观察这几个实体类,我们发现这几个类都是没有继承结构的。没错,因为LitePal进行表管理操作时不需要这些实体类有任何的继承结构,当时为了简单起见就没有写。但是进行CRUD操作时就不行了,LitePal要求所有的实体类都要继承自LitePalSupport 这个类,因此这里我们就要把继承结构给加上才行。修改News类的代码,如下所示:

public class News extends LitePalSupport {
    ......
    // 自动生成get、set方法
}

可以看到,这里只是让News类继承自了LitePalSupport ,其它什么都没有改变。另外几个Comment、Man、Woman类也使用同样的改法,这里就不一 一演示了。

继承了LitePalSupport 类之后,这些实体类就拥有了进行CRUD操作的能力,那么比如想要存储一条数据到news表当中,就可以这样写:

News news = new News();
news.setTitle("这是一条新闻标题");
news.setContent("这是一条新闻内容");
news.setPublishDate(new Date());
news.save();

只需要new出一个News对象,然后把要存储的数据通过setter方法传入,最后调用一下save()方法就好了,而这个save()方法自然就是从LitePalSupport 类中继承而来的了。

除此之外,save()可以根据返回值来判断存储是否成功,比如说这样写:

if (news.save()) {
    Toast.makeText(context, "存储成功", Toast.LENGTH_SHORT).show();
} else {
    Toast.makeText(context, "存储失败", Toast.LENGTH_SHORT).show();
}

save()方法返回的是一个布尔值,用于表示存储成功还是失败,但同时也说明这个方法是不会抛出异常的。有些朋友希望如果存储失败的话就抛出异常,而不是返回一个false,那就可以使用saveThrows()方法来代替,如下所示:

News news = new News();
news.setTitle("这是一条新闻标题");
news.setContent("这是一条新闻内容");
news.setPublishDate(new Date());
news.saveThrows();

使用saveThrows()方法来存储数据,一旦存储失败就会抛出一个LitePalSupportException异常,我们可以通过对这个异常进行捕获来处理存储失败的情况。

但LitePal中的save()方法返回的是布尔值,怎样才能拿到存储成功之后这条数据对应的id呢?LitePal使用了一种非常巧妙的做法,还记得我们在每个实体类中都定义了一个id字段吗?当调用save()方法或saveThrows()方法存储成功之后,LitePal会自动将该条数据对应的id赋值到实体类的id字段上。让我们来做个试验吧,代码如下所示:

        News news = new News();
        news.setTitle("Android Q");
        news.setContent("最新一代人工智能手机");
        news.setPublishDate(new Date());
        Log.d(TAG, "news id is " + news.getId());
        news.save();
        Log.d(TAG, "news id is " + news.getId());

在save之前打印一下news的id,在save之后再打印一次,现在运行一下,打印结果如下所示:

2020-01-14 09:46:22.398 1982-1982/com.example.sqlitefeel D/MainActivity: news id is 0
2020-01-14 09:46:22.478 1982-1982/com.example.sqlitefeel D/MainActivity: news id is 1

在save之前打印的id是0,说明此时id这个字段还没有被赋值,在save之后打印的id是1,说明此时id已经被赋值了。那么我们再到数据库表中再查看一下这条记录到底有没有存储成功吧,如下图所示:

sqlite> select * from news;
1|最新一代人工智能手机|1578966382398|Android Q

可以看到,这条新闻确实已经存储成功了,并且对应的id正是1,和我们前面打印的结果是一致的。

LitePal在存储数据的时候默默帮我们做了很多的事情,比如多个实体类之间有关联关系的话,我们不需要考虑在存储数据的时候怎么去建立数据与数据之间的关联,LitePal都帮我们做好了。

咱们搞个列子,Comment和News之间是多对一的关系,一条News有多条评论,因此我们就可以这样写:

Comment comment1 = new Comment();
comment1.setContent("爱你哦!");
comment1.setPublishDate(new Date());
comment1.save();
Comment comment2 = new Comment();
comment2.setContent("喜欢你!");
comment2.setPublishDate(new Date());
comment2.save();
News news = new News();
news.getCommentList().add(comment1);
news.getCommentList().add(comment2);
news.setTitle("Android智能手机");
news.setContent("最新版本Q已发布");
news.setPublishDate(new Date());
news.setCommentCount(news.getCommentList().size());
news.save();

这里先是存储了一条comment1数据,然后存储一条comment2数据,接着在存储News之前先把刚才的两个Comment对象添加到了News的commentList列表当中,这样就表示这两条Comment是属于这个News对象的,最后再把News存储到数据库中,这样它们之间的关联关系就会自动建立了。让我们查看数据库表检查一下吧,首先看一下news表,如下所示:


image.png

OK,第二条新闻已经成功存储到news表中了,这条新闻的id是2。那么从哪里可以看出来关联关系呢?我们在上一篇文章中学过,多对一关联的时候,外键是存放在多方的,因此关联关系我们要到comment表中去查看,如下所示:


image.png

可以看到,两条评论都已经成功存储到comment表中了,并且这两条评论的news_id都是2,说明它们是属于第二条新闻的。上面的代码只是多对一情况的一种用法,还有一对一和多对多的情况,其实用法都是差不多的,相信你已经能举一反三了。

另外,LitePal对集合数据的存储还专门提供了一个方法,比如说我们有一个News集合,那么应该怎样去存储这个集合中的每条News呢?传统情况下可以这样写:

List<News> newsList;
...
for (News news : newsList) {
    news.save();
}

通过一个循环来遍历出这个集合中的每一个News对象,然后逐个调用save()方法。这样的写法效率低,调用save()方法的时候除了会执行存储操作之外,还会去分析News类的关联关系,那么每次循环都去重新分析一遍关联关系显然是比较耗时的。因此,LitePal提供了一个saveAll()方法,专门用于存储集合数据的,用法如下所示:

List<News> newsList;
...
LitePal.saveAll(newsList);

saveAll()方法接收一个Collection集合参数,只要把待存储的集合数据传入即可。这个方法可以完成和上面一段代码完全一样的功能,但效率却会高得多,而且写法也更加简单。

LitePal中提供的存储操作全部都学完了,下一篇文章当中会开始讲解更新和删除操作的用法。感兴趣的朋友请继续阅读 Android数据库高手秘籍(六)LitePal的修改和删除操作

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容