商城菜鸟商城学习笔记Android 开发技术分享

12-购物车数据存储开发中使用开源ORM框架操作数据库

2016-08-04  本文已影响454人  小楠总

一、前言

好吧,在正式记录今天的开发笔记之前,先说一些题外话吧。今天(2016年2月3日)本来是个不错的天气,但是由于昨天晚上乱吃东西,今天起来又呕又吐,肚子疼,拉肚子。。。。(好恐怖有木有!)本类跟别人约好去打球的结果没打成,心中真是一万只草泥马在崩腾啊~

由于直接把Word文档中的文章复制到QQ空间日志不能显示图片,因此我以后尽量减少使用图片吧,大家也可以到我的网盘去下载源word文件。

二、商城应用中购物车数据的存储

商城APP中,我们需要把用户的添加到购物车的商品信息保存起来,其中每一条数据包含商品的基本信息(ID,图片,名字,介绍,价格等)以及用户添加的该商品的数量。

购物车数据存储在哪里?对于这个问题,解答有两个:

  1. 保存在云端(服务器)。如果我们的客户端有Android版本,IOS版本,Web版本等多版本的时候,这种方式可以进行不同版本的数据同步。因此,多版本下,必须使用这种方式存储购物车数据。
  2. 保存在客户端的系统的本地。

由于我们的APP开发只有Android版本,因此使用本地的方式存储购物车数据。

那么问题又来了,如果保存在本地,应该如何保存?

Android中常用的数据存储方式有:

至于三种方式的区别这里不赘述,详细请去百度Android中常用的数据存储方式以及区别和使用。

我们的视频教程中使用SharePreference存储购物车数据:通过把List中的Bean对象转换为JSON字符串数据来存起来,取出来的时候通过Gson重新把JSON转换为Bean对象。在内存中维护了两个数组,一个是我们常用的ArrayList,一个是稀疏数组SparseArray,ArrayList用于Adapter的展示,SparseArray主要用于存储(与JSON对象之间的转换)。由于我们每一条Bean都是通过ID来区分的,因此一开始使用Map<int id , Bean b>的方式来存储,但是Android Studio只能地提示我们使用SparseArray,因为SparseArray对键是int类型的Map做过优化。

但是,这种方式需要同时维护两个数组,显然比较麻烦。因此我个人考虑使用其他方法来存储购物车数据--数据库。但是众所周知数据库的操作以及配置比较麻烦,还得去学习数据库的SQL语句。但是幸好我们有开源ORM框架。下一节将开始介绍。

三、Android中开源ORM框架LitePal介绍

本次笔记介绍GitHub上面非常著名的一个数据库操作依赖库,LitePal。LitePal是一款开源的Android数据库操作映射框架,它采用了对象关系映射(ORM)的模式,并将我们平时开发时最常用到的一些数据库功能进行了封装,使得不用编写一行SQL语句就可以完成各种建表、増删改查的操作。并且LitePal很“轻”,jar包只有100k不到,而且近乎零配置,这一点和Hibernate这类的框架有很大区别。目前LitePal的源码已经托管到了GitHub上,地址是 https://github.com/LitePalFramework/LitePal

实为了方便我们对数据库表进行管理,其实Android本身就提供了一个帮助类:SQLiteOpenHelper。这个类集创建和升级数据库于一身,并且自动管理了数据库版本,算是一个非常好用的工具。SQLiteOpenHelper是一个抽象类,这意味着如果我们想要使用它的话,就需要创建一个自己的帮助类去继承它。SQLiteOpenHelper中有两个抽象方法,分别是onCreate()和onUpgrade(),我们必须在自己的帮助类里面重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑。

上文提到过,与传统的数据库使用不同,LitePal框架采取的是对象关系映射(ORM)的模式,那么什么是对象关系映射呢?简单点说,我们使用的编程语言是面向对象语言,而我们使用的数据库则是关系型数据库,那么将面向对象的语言和面向关系的数据库之间建立一种映射关系,这就是对象关系映射了。但是为什么要使用对象关系映射模式呢?这主要是因为大多数的程序员都很擅长面向对象编程,但其中只有少部分的人才比较精通关系型数据库。而且数据库的SQL语言晦涩难懂,就算程序员很精通它,恐怕也不喜欢经常在代码中去写。而对象关系映射模式则很好地解决了这个问题,它允许程序员使用面向对象的方式来操作数据库,从而可以从晦涩难懂的SQL语言中解脱出来。

四、LitePal的基本使用以及注意点

1,LitePal的引入以及数据库的创建

用LitePal来操作数据库,首先应该在Gradle的配置文件当中把LitePal框架引入到项目中,代码如下:

compile 'org.litepal.android:core:1.3.0'

Application中配置LitePal,在自己的Application中的onCreate方法中进行LitePal的初始化:
由于操作数据库时需要用到Context,而我们显然不希望在每个接口中都去传一遍这个参数,那样操作数据库就显得太繁琐了。因此,LitePal使用了一个方法来简化掉Context这个参数,只需要继承LitePalApplication,然后在AndroidManifest.xml中配置一下LitePalApplication,所有的数据库操作就都不用再传Context了。

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        LitePalApplication.initialize(this);
    }
}

将Application配置为自己的Application:

<application
        android:name=".MyApplication">
        .......
</application>

2,使用LitePal创建基本表

根据对象关系映射模式的理念,每一张表都应该对应一个模型(Model),也就是说,如果我们想要建一张X表,就应该有一个对应的X模型类。所以应该新建一个X类,并且继承DataSupport类,写上必须的字段。其中id这个字段可写可不写,因为即使不写这个字段,LitePal也会在表中自动生成一个id列,但是最好写上,毕竟每张表都一定要有主键的。最后需要在上述的XML代码中配置一下。

这里要特别说明一下,LitePal的映射规则是非常轻量级的,不像一些其它的数据库框架,需要为每个模型类单独配置一个映射关系的XML,LitePal的所有映射都是自动完成的。根据LitePal的数据类型支持,可以进行对象关系映射的数据类型一共有8种,int、short、long、float、double、boolean、String和Date。只要是声明成这8种数据类型的字段都会被自动映射到数据库表中,并不需要进行任何额外的配置。既然是自动映射的话,如果X类中有一个字符串字段并不想让它映射到数据库表中,这时候LitePal同样采用了一种极为轻量的解决方案:只有声明成private修饰符的字段才会被映射到数据库表中,如果你有某一个字段不想映射的话,只需要将它改成public、protected或default修饰符就可以了。

接着开始动手创建基本表,比如我的基本表需要存储Bean对象的数据,那么创建Bean的java类把,最好把成员long id加上,注意这个对象必须继承DataSupport。例子:

import org.litepal.crud.DataSupport;

/**
 * litepal的bean对象
 */
public class Bean extends DataSupport {


    private long id;

    private String name;

    public Bean() {
    }

    public Bean(String name, long id) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
}

接着在项目的assets目录(Android Studio中,assets目录创建方法:把当前空间从“Android”转到“Project”,打开工程下面的“APP”目录,选中“main”右击新建文件夹“assets”),下面新建一个litepal.xml文件,并将以下的XML配置代码代码拷贝进去。其中ShoppingCart标签是数据库名,version是数据库版本。list标签底下的mapping标签是表,也就是我们创建好的用于存储Bean对象数据的表。

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname value="ShoppingCart"/>
    <version value="1"/>
    <list>
        <mapping class="com.nan.recycleviewdemo.bean.Bean"/>
    </list>
</litepal>

3,使用LitePal对基本表进行基本操作(增删改查)
插入:下面的代码是在笔记表中插入一条数据。LitePal操作数据是通过使用面型对象编程的,因此通过创建对象并且设置各个键的值就可以非常方便地插入一条新数据最后只需要调用save()方法保存到本地数据库就可以了。

Bean b = new Bean("new data ", id);
//添加数据需要调用保存方法
b.save();
    删除:先得到我们的bean对象,然后调用DataSupport的方法进行删除。
//先得到我们的bean对象,然后调用DataSupport的方法进行删除
Bean bean = mDatas.get(position);

DataSupport.delete(Bean.class, bean.getId());

    修改:以笔记表为例,需要先判断数据是否已经保存过,如果是,就可以修改数据了,具体操作就是调用set()方法。最后保存一下就可以了。

if(bean.isSaved()) {
    bean.setName(.....);
    bean.save();
}

查询:通过DataSupport的find方法,通过ID查找我们的bean对象。

Bean b = DataSupport.find(Bean.class, id));

五、DataSupport的的重要方法以及使用注意点

由上面的介绍知道,LitePal的很多数据库操作都是通过DataSupport来进行的,因此我们有必要去了解DataSupport这个类的一些常用而且重要方法(参数省略)。

//查找某一个bean对象
DataSupport.find();
//找出所有bean对象,返回List<Bean>
DataSupport.findAll();
//删除一个bean对象
DataSupport.delete();
//删除所有bean对象
DataSupport.deleteAll();
//求某一列的平均值
DataSupport.average();
//求所有数据的数量
DataSupport.count();
//排序
DataSupport.order();
//求某一列的的最小值的对象
DataSupport.min();
//求某一列的的最大值的对象
DataSupport.max();
//保存所有bean对象
DataSupport.saveAll();

Litepal使用的注意点(仅仅列出一些常见的):

1、当调用DataSupport的save()方法一直返回错误(false)的时候,很有可能是我们的java bean对象以及对应的配置有误,错误有可能如下:

bean对象以及bean对象的父类,内部类,一切bean对象文件里面出现过的类,一定要继承DataSupport类,并且在litepal.xml文件中配置。不继承,不配置,都会报错。
如果bean对象添加了成员变量id,那么id一定要是int 或者 long 类型,其他类型均会报错。
如果我们的对象只有一个成员id,例如我们的BaseBean经常就是只有一个成员id,那么项目运行起来,在创建基本表的时候依然会报错。原因是:不管是否添加id,litepal都会自动为我们添加id这个属性,因此表明litepal的一个bean对象不能只有一个名字为id成员。如果是有一个id,那么litepal在底层生成SQL语句的时候,会生成“id integer primary key autoincrement , ”这是一句不完整的SQL语句,因此会报错。

2、save()方法一直返回错误(false)的时候,异常信息都是警告而不是错误,因此需要切换LogCat的过滤。

3、对于findAll()方法,它返回的是List<Bean对象>,因此需要我们去强制转换为ArrayList<T>,不然在add等操作的时候会报错,因为我们使用的都是List的实现类而不是List接口本身。强转如果不指定泛型T的时候Android Studio会提示没有类型检查的警告,但是我们可以忽略。

4、bean对象的所有成员变量的名字都不能和SQL的一且关键字冲突,原因也很简单,litepal在底层生成SQL语句的时候会把成员变量的名字拼成SQL语句。

5、成员如果是boolean a;

其中a是我举例子用的名字,生成get 以及 set方法的时候,Android Studio会把get方法名定义为“public boolean isA(boolean a)”,我们自己不要手贱把它改为getA ,否则 litepal也会报找不到方法的错。

6、额,最后一点是数据库的问题,因为id属性是默认自增长的,如果项目中自定义的ID不是自增长的话,最好自己再定义一个ID。比如商城项目中的商品ID,如果用户不是按照逐次增长的形式添加商品的话,商品被save()的时候,一开始是ID+1的,知道ID满足与已存在的商品ID自增长的规律的时候才能正确判断商品已存在。结论就是,使用Litepal的时候,数据库默认id好像更改不了它的自增长性质,因此我们使用Litepal的时候如果有自己的ID,最好还是自己新增加一个ID吧。

好了今天的笔记到这里了,再贱ヾ( ̄▽ ̄)ByeBye

如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:

公众号:Android开发进阶

我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)

上一篇下一篇

猜你喜欢

热点阅读