Android持久化存储(4)greenDAO的使用
1.背景
在上篇博客介绍SQLite的使用我们能感觉到,虽然Android已经简化了一些SQLite的操作,提供了较为方便的API,但使用中还是需要开发者写一些SQL语言,简单而不简约,有时候只想存储一些简单数据,却需要花费很大力气去开发接口,当然你可以说让另一个程序员去开发数据库操作接口不就行了吗,你老板肯定不同意,这么简单的活还要找别人,本来招你就是想一个人当两个人用,你还奢望一份工作两个人干?!如果你为这个事发愁,那赶紧来看看今天要介绍的greenDAO。
2.什么是GreenDAO
greenDAO官网关于greenDAO的介绍直击开发者痛点—摆脱编写SQL的泥沼!如果觉得这个slogan还不是很清楚,可以看一下详细的介绍:
greenDAO是一个开放源代码的Android ORM,令开发SQLite数据库变得更有趣。它使开发人员免于陷入处理低级数据库泥沼,节省了开发时间。 SQLite是一个很棒的嵌入式关系数据库,然而编写SQL和解析查询结果仍然是非常繁琐且耗时的任务。通过将Java对象映射到数据库表(称为ORM,“对象/关系映射”),greenDAO使您摆脱这些麻烦。这样,您可以使用简单的面向对象的API来存储,更新,删除和查询Java对象。
greenDAO具有如下优势
- 高性能,可能是最快的Android ORM(虽然有可能违法广告法,但确实疗效不错);
- 易于使用的强大API;
- 内存消耗小;
- 库体积小;(<100KB);
- 支持数据库加密:greenDAO支持SQLCipher,以确保用户数据的安全
greenDAO如何做到简化数据库操作呢?因为使用了ORM,即对象关系映射(Object Relational Mapping),对象指业务实体对象(这里指java对象),关系指关系型数据库,通过将关系型数据库和业务实体对象之间作一个映射,开发人员只和对象打交道,不用面对繁琐的SQL语言,对象到数据库的映射由中间件帮忙映射,greenDAO正是扮演这样的角色。
3.greenDAO的使用
3.1 工程中添加greenDAO
greenDAO如此方便,那么在哪里下载到呢?又如何添加到工程中呢?在工程中配置很简单,只需要配置两个build.gradle
文件,首先是工程根目录下的build.gradle
,第一步是在仓库repositories里添加mavenCentral
,因为greenDAO放在Maven Central上,第二步是在依赖dependencies中添加greenDAO,请注意使用最新版本,可在这个网址查询版本号。
buildscript {
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' //
}
}
第二个要修改的build.gradle
是应用目录下的app/build.gradle
,首先是声明使用greenDAO,其次是配置greenDAO选项,最后在依赖中添加greenDAO。
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao'
android {
...
}
//在这里设置greenDAO的配置选项
greendao {
schemaVersion 2
daoPackage "com.test.greendaodemo"
}
//build.gradle里的依赖模块
dependencies {
implementation 'org.greenrobot:greendao:3.2.2'
}
其中,greenDAO里配置支持多个属性配置,分别如下:
- schemaVersion: 数据库的当前版本。如果更改实体/数据库架构,则必须增加该值,如果不配置该选项,则数据库版本默认为1;
- daoPackage: 生成的DAO,DaoMaster和DaoSession的程序包名称。默认为实体所在的程序包名;
- targetGenDir: 生成代码的存储位置。 默认是build目录下(build / generated / source / greendao);
- generateTests: 设置成true以自动生成单元测试;
- targetGenDirTests: 生成的单元测试存储目录。默认为src / androidTest/java。
配置完两处gradle之后,程序中便可以开始使用greenDAO了。
3.2 创建实体类
例如我们创建一个Book的实体类,这一步类似于创建数据库的表,只不过这里操作的是对象。Book实体类的代码如下,这个实体类就是一般的java代码,还不能和数据库进行映射,为了用上greenDAO,还需要对这个实体类进行注解,或者说打上标记,实现很简单,在class上使用@Entity
即可,这样就变成greenDAO可识别的实体类(没看过greenDAO源代码,猜测greenDAO会扫描所有代码文件,发现了这个标记识别成要映射的实体类)。
我们在创建数据库的表时,对每一列的要求可能不一样,例如想把某一列设置成自增长,某一列值不能为空等,实体类是不是也可以这么设置呢,答案是可以,想设置哪个变量(或者说是哪一列,因为实体类中的变量会转换成数据库的列名),在该变量声明上打上标记就像,例如想设置id
为自增长主键,那就在id
之上添加@Id(autoincrement = true)
(注意,greenDAO要求主键必须是long类型),要设置ISBN为非空列,那就添加注解@NotNull
,或者想把某个变量排除在外,不写入数据表,那就添加注解@Transient
。Book实体类完整示例如下
package com.test.greendaodemo;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.NotNull;
import org.greenrobot.greendao.annotation.Transient;
import org.greenrobot.greendao.annotation.Generated;
@Entity
public class Book {
@Id(autoincrement = true)
private long id;
private String name;//书名
@NotNull
private long ISBN;//国际标准书号
private String author;//作者
private float price;//价格
@Transient
private String press;//出版社
@Generated(hash = 1424927682)
public Book(long id, String name, long ISBN, String author, float price) {
this.id = id;
this.name = name;
this.ISBN = ISBN;
this.author = author;
this.price = price;
}
@Generated(hash = 1839243756)
public Book() {
}
//getter setter
public long getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getISBN() {
return ISBN;
}
public void setISBN(long ISBN) {
this.ISBN = ISBN;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getPress() {
return press;
}
public void setPress(String press) {
this.press = press;
}
public void setId(long id) {
this.id = id;
}
}
实体类设置完之后,点击make project,greenDAO便根据这个实体类自动生成BookDao,DaoMaster
和DaoSession
三个文件,因为没在app/build.gradle
里设置greendao的targetGenDir
,因此生成的三个文件路径放在默认路径build/source/greendao
下。如果想放置到java代码目录下,设置targetGenDir
成指定目录即可。个人建议使用默认地址,因为这是自动生成的代码,不需要开发者去修改,如果放在java目录下,不了解greenDAO的开发人员误认为是人工写的代码,反而可能去修改其中的代码导致出错。
虽然是自动生成的代码,但还是需要了解一下生成的这个代码文件是做啥的。
- DaoMaster:点击打开DaoMaster,可以看到代码封装了SQLiteDatabase和SQLiteOpenHelper(DatabaseOpenHelper继承了SQLiteOpenHelper),这表示DaoMaster功能是创建和升级SQLite数据库,也是使用greenDAO的入口;
- BookDAO:对于每个实体,greenDAO生成对应的DAO,因示例代码只创建了Book实体,故只生成了BookDAO,一般是名字为
xxx
的实体,会生成的DAO是xxxDAO
,DAOs里包括根据实体创建表的方法,读取等方法; - DaoSession:这个类管理所有可用DAO对象,例如示例中的BookDao,可通过使用getter方法获取该对象。
这三个文件又有怎样的关系呢,DaoMaster是入口,通过其获得DaoSession,而DaoSession又管理着所有DAO,因此可以通过DaoSession获得DAO对象,他们的关系图如下图所示,我们将会在实际使用的时候再理解一下他们的关系。
3.3 greenDAO初始化
创建一个application类,然后在application中完成DaoSession的初始化,这样的好处是依托于Application单例模式,可避免以后重复初始化greenDAO,代码如下,别忘了在AndroidManifest.xml里增加android:name=".MyApplication"
。
package com.test.greendaodemo;
import android.app.Application;
import android.database.sqlite.SQLiteDatabase;
public class MyApplication extends Application {
private DaoMaster.DevOpenHelper mHelper;
private SQLiteDatabase db;
private DaoMaster mDaoMaster;
private DaoSession mDaoSession;
public static MyApplication instances;
@Override public void onCreate() {
super.onCreate();
instances = this;
setDatabase();
}
public static MyApplication getInstances(){
return instances;
}
/**
* 设置greenDao
*/
private void setDatabase() {
// 通过 DaoMaster的内部类DevOpenHelper可获得SQLiteOpenHelper对象。
mHelper = new DaoMaster.DevOpenHelper(this, "greenDAOdemo_db", null);
db = mHelper.getWritableDatabase();
mDaoMaster = new DaoMaster(db);
mDaoSession = mDaoMaster.newSession();
}
public DaoSession getDaoSession() {
return mDaoSession;
}
public SQLiteDatabase getDb() {
return db;
}
}
3.4 使用greenDAO实现增删改查
实现增删改查需要获取DAO对象,如何取得DAO对象呢?回忆一下上边提到的greenDAO生成的三个文件关系图,还有印象的话,可知道获取DAO对象需要通过DaoSession,而获取DaoSession又是通过DaoMaster。有了DAO对象,可很方便的实现增删改查,基本上只需要实例化Book对象,配置Book对象各个属性的值,再使用BookDao对应的增删改查方法就能简单快速执行对应的操作,示例代码如下,从示例代码可以看到,增删改查全程没见到烦人的SQL语句,因为greenDAO替我们去生成和执行对应的SQL语句了。
BookDao mbookdao = MyApplication.getInstances().getDaoSession().getBookDao();
//增
book = new Book();
book.setId((long)2);
book.setName("三体");
book.setISBN((long)89327455);
book.setAuthor("刘慈欣");
book.setPrice((float)50.00);
book.setPress("重庆出版社");
mbookdao.insert(book);
//删
mbookdao.deleteByKey((long)1);
//改
book.setPrice((float)30.00);
mbookdao.update(book);
//查
List<Book> booklist = mbookdao.loadAll();
String bookname = "";
StringBuilder stringBuilder=new StringBuilder();
for (int i = 0; i < booklist.size(); i++) {
bookname += booklist.get(i).getName()+",";
stringBuilder.append(booklist.get(i).getId()+"\n");
stringBuilder.append(booklist.get(i).getName()+"\n");
stringBuilder.append(booklist.get(i).getAuthor()+"\n");
stringBuilder.append(booklist.get(i).getISBN()+"\n");
stringBuilder.append(booklist.get(i).getPress()+"\n");
}
4.总结
greenDAO通过ORM方案,将实体类和数据库映射,避免程序员直接面对SQL语言,大大简化了SQLite数据库开发流程,如果只是简单的数据库存储操作,大可借助greenDAO来开发,因为greenDAO使用简单,配置简单,占用内存小,处理速度快,而且还是开源的,有好的*先用着吧,先把老板安排的工作做好,待到实力大增还有时间,再想办法自己造*或者优化*,这是后话了。