每天学习一个Android中的常用框架——2.greenDao
文章目录
- 1.简介
- 2.特性
- 3.核心
- 4.演示
- 4.1 集成
- 4.2 配置
- 4.3 创建数据库
- 4.4 初始化
- 4.5 升级数据库
- 4.6 加密数据库
- 4.7 插入数据
- 4.8 查询数据
- 4.9 更新数据
- 4.10 删除数据
- 5.源码地址
1.简介
上一篇博客中,我们介绍了集成和使用都比较方便的数据持久层框架——Litepal,而在这篇博客中,我将介绍另一个当前更为主流的框架,也就是greenDao。
事实上,之前学习Android的时候在做持久化这一块时,使用的更多是原生的Sqlite或者Litepal,对于greenDao,一直都是只听说过而没有深入使用,今天趁着框架学习的兴头,就简单学习了一下greenDao,并且将学习过程记录下来,供各位读者参考。
2.特性
为什么要使用greenDao?通过GreenDao,我们可以更快速的操作数据库,我们可以使用简单的面相对象的API来存储,更新,删除和查询Java对象。
事实上,greenDao有些类似于Litepal,不过集成和使用要相对比Litepal要复杂些,正因如此,它的功能也更加强大。它的主要特性如下:
-
高性能,下面是官方给出的关于GreenDao,OrmLite和ActiveAndroid三种ORM解决方案的数据统计图:
-
易于使用的强大API,涵盖关系和连接;
-
最小的内存消耗;
-
占用内存小(<100KB)以保持较低的构建时间并避免65k方法限制;
-
数据库加密:greenDAO支持SQLCipher,以确保用户的数据安全;
相对于Litepal来说,greenDao可能更适用于较正式的开发场景,所以我们同样需要认真地学习该框架爱。
3.核心
在正式使用greenDao之前,我们应该先简单了解一下greenDao这个框架内部的核心,这样对于我们使用greenDao大有裨益
GreenDao的核心类有三个:分别是DaoMaster,DaoSession,XyzDao,这三个类都会自动创建,无需自己编写创建!不要惊讶,在后面的演示中,你将会体验到这个神奇的功能。
- DaoMaster:DaoMaster保存数据库对象(SQLiteDatabase)并管理特定模式的DAO类(而不是对象)。它有静态方法来创建表或删除它们。它的内部类OpenHelper和DevOpenHelper是SQLiteOpenHelper实现,它们在SQLite数据库中创建模式。
- DaoSession:管理特定模式的所有可用DAO对象,您可以使用其中一个getter方法获取该对象。DaoSession还提供了一些通用的持久性方法,如实体的插入,加载,更新,刷新和删除。
- XyzDao:数据访问对象(DAO)持久存在并查询实体。对于每个实体,greenDAO生成DAO。它具有比DaoSession更多的持久性方法,例如:count,loadAll和insertInTx。
- XyzEntity :可持久化对象。通常,实体对象代表一个数据库行使用标准 Java 属性(如一个POJO 或 JavaBean )。
我们简单了解了一下核心,当然只是比较浅显的部分,不过对于我们的简单使用也已然足够。
4.演示
4.1 集成
greenDao的集成相较于Litepal要多出一个步骤,即集成插件,首先我们还是在module下的build.gradle先导入greenDao,代码如下:
buildscript { repositories { jcenter() mavenCentral() // add repository } dependencies { classpath 'com.android.tools.build:gradle:3.5.3' classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0' // add plugin }}
依赖导入后,接下来在项目下的build.gradle(注意和导入依赖的同名文件作区分)导入插件相关,代码如下:
apply plugin: 'com.android.application'apply plugin: 'org.greenrobot.greendao' // apply plugin dependencies { implementation 'org.greenrobot:greendao:3.3.0' // add library}
搞定这两项后,重新sync一下,greenDao就集成到你的项目里了。
4.2 配置
跟Litepal类似的,grennDao在集成完毕后,同样需要一些简单的配置,才能确保可以正常使用。
在module下的build.gradle先对greenDao进行配置,主要是在android闭包下配置grenndao闭包,这里贴出全部的代码,方便读者参考,代码如下:
apply plugin: 'com.android.application'apply plugin: 'org.greenrobot.greendao' // apply pluginandroid { compileSdkVersion 29 buildToolsVersion "29.0.3" defaultConfig { applicationId "com.androidframelearn.dao_greendao" minSdkVersion 16 targetSdkVersion 29 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } greendao { schemaVersion 1 //当前数据库版本 daoPackage 'com.androidframelearn.dao_greendao' // dao的包名,包名默认是entity所在的包 targetGenDir 'src/main/java' // 生成数据库文件的目录 // generateTests false //设置为true以自动生成单元测试。 // targetGenDirTests 'src/main/java' //应存储生成的单元测试的基本目录。默认为 src/androidTest/java。 }}dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'org.greenrobot:greendao:3.3.0' // add library implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'}
其中,对grenndao闭包中的属性做一些解释:
- schemaVersion:指定数据库schema版本号,迁移、更新等操作会用到;
- daoPackage :dao的包名,包名默认是entity所在的包;
- targetGenDir:生成数据库文件的目录;
- generateTests:设置是否开启单元测试;
- targetGenDirTests:生成单元测试文件的目录;
一般来说,我们只是想简单使用的话,配置前三项即可,后两项在这里注释掉了,读者可以根据需求进行配置。
与上一小节相同,sync一下,即将greenDao配置完成。
4.3 创建数据库
跟Litepal一样,greenDao同样采取了对象关系映射(ORM)的模式,即我们想使用greenDao,同样需要创建一个实体类。为了跟上个项目相对比,我们同样新建一个名为Book的实体类。之前有提到过,要想让greenDao为我们自动三个类,这里就要用greenDao要求的写法来编写实体类,即使用@Entity
将该实体类标识为存储的数据类。在该类中,我们只需要定义属性,以及相应的注解,不需要编写相应的get/set
方法,代码如下:
@Entitypublic class Book { @Id(autoincrement = true) //设置自增长 private long id; private String author; private double price; private int pages; @Unique//设置唯一性 private String name;}
PS:用注解开发将类注入的形式有点像Java中的Spring系列框架,如果比较了解的读者应该能明白这个意思
在进行下一步之前,先来简单介绍一下greenDao中主要的注解:
@Entity
:表示这个实体类一会会在数据库中生成对应的表;@Id
:表示该字段是id,注意该字段的数据类型为包装类型Long;@Property
:则表示该属性将作为表的一个字段,其中nameInDb看名字就知道这个属性在数据库中对应的数据名称;@Transient
:该注解表示这个属性将不会作为数据表中的一个字段;@NotNull
:表示该字段不可以为空;@Unique
:表示该字段唯一;
有兴趣的读者可以自行尝试这些注解,这里只使用比较基础的注解作为演示。
当我们编写好了实体类之后,若使用的IDE为Android Studio,只需按下 Ctrl + F9或者选择菜单中Build -> Make Project,等待几秒钟,神奇的事情就发生了!刚刚我们编写好的Book实体类自动产生了get/set
方法,并且发生了一些变化,俨然变成了这样:
package com.androidframelearn.dao_greendao;import org.greenrobot.greendao.annotation.Entity;import org.greenrobot.greendao.annotation.Id;import org.greenrobot.greendao.annotation.Index;import org.greenrobot.greendao.annotation.Generated;@Entitypublic class Book { @Id(autoincrement = true) //设置自增长 private long id; private String author; private double price; private int pages; @Index(unique = true)//设置唯一性 private String name; @Generated(hash = 368601420) public Book(long id, String author, double price, int pages, String name) { this.id = id; this.author = author; this.price = price; this.pages = pages; this.name = name; } @Generated(hash = 1839243756) public Book() { } public long getId() { return this.id; } public void setId(long id) { this.id = id; } public String getAuthor() { return this.author; } public void setAuthor(String author) { this.author = author; } public double getPrice() { return this.price; } public void setPrice(double price) { this.price = price; } public int getPages() { return this.pages; } public void setPages(int pages) { this.pages = pages; } public String getName() { return this.name; } public void setName(String name) { this.name = name; }}
除此之外,greenDao也确确实实给我们自动生成了三个类,如下图中的红框标出:
如果做到这一步都没有什么问题的话,就说明Book这个实体类已经“托管”到greenDao中,我们可以对它进行相应的CRUD操作了。但在这之前,还需要进行以下初始化。
4.4 初始化
在使用greenDao对实体类Book进行CRUD操作之前,我们需要对greenDao进行一个简单的初始化。新建一个Myapplication集成Application,在应用被创建的同时执行相应的初始化逻辑,并且使用单例模式封装Myapplication,供外部调用,代码如下:
package com.androidframelearn.dao_greendao;import android.app.Application;import android.database.sqlite.SQLiteDatabase;import android.util.Log;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; // 初始化GreenDao initDatabase(); } /** * 初始化greenDAO */ private void initDatabase() { /**通过 DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的 SQLiteOpenHelper 对象。 可能你已经注意到了,你并不需要去编写「CREATE TABLE」这样的 SQL 语句,因为 greenDAO已经帮你做了。 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。**/ mHelper = new DaoMaster.DevOpenHelper(this, "androidframelearn.db", null); db = mHelper.getWritableDatabase(); // 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。 mDaoMaster = new DaoMaster(db); mDaoSession = mDaoMaster.newSession(); Log.i("GreenDao","数据库初始化成功!"); } public DaoSession getDaoSession() { return mDaoSession; } public static MyApplication getInstances(){ return instances; }}
当然,若自定义了Application,记得在清单文件里配置一下android:name
属性,不然默认不会调用,清单文件的代码如下:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.androidframelearn.dao_greendao"> <application android:name=".MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> intent-filter> activity> application>manifest>
与此同时,跟Litepal一样的,我们在使用greenDao之前对一些必要的实例进行一些初始化,修改MainActivity,通过刚刚定义的MyApplicaiton获取到Daosession的实例,再使用Daosession对象获取到BookDao的实例,代码如下:
private void createDBbyGreenDao() { btn_db_create.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 获取daosession对象 mDaoSession = MyApplication.getInstances().getDaoSession(); mBookDao = mDaoSession.getBookDao(); Log.i(TAG,"创建数据库成功"); } }); }
接下来,我们正式开始相关数据操作的演示。
为了演示方便和有对比性,这里使用的布局和上一篇讲解Litepal中activity_main.xml的布局是一样的,布局代码这里就不再贴出了,读者可以参考上篇博客的布局,也可以自己编写,反正怎么方便怎么来吧。
4.5 升级数据库
在开始讲解CRUD操作之前,我们简单提及一下数据库相关的方法。
一般来说,如果只是简单地进行升级,步骤大抵如下:
- 在module的build.gradle文件中升级版本号,即
schemaVersion
- 修改实体类
- 重新编译项目即可
而稍微复杂一些的数据库升级情况,例如数据库迁移等,greenDao的OpenHelper
下有个 onUpgrade(Database db, int oldVersion, int newVersion)
方法,当设置的数据库版本改变时,在数据库初始化的时候就会回调到这个方法,我们可以通过继承OpenHelper重写onUpgrade
方法来实现数据库更新操作,步骤大抵如下:
- 创建临时表TMP_,复制原来的数据库到临时表中;
- 删除之前的原表;
- 创建新表;
- 将临时表中的数据复制到新表中,最后将TMP_表删除掉;
升级数据库的操作建议参看greenDao上的官方文档(作者本地被墙,没法上网查看),这里不再赘述。
4.6 加密数据库
开发中对于存储于数据库中的敏感数据,我们可以通过对数据库加密来进行保护。greenDao可以通过SQLCipher来进行加密处理。下面我们简单讲解下加密过程:
步骤:
- 导入加密库文件依赖:
implementation 'net.zetetic:android-database-sqlcipher:3.5.6'
- 修改DaoSession的生成方式:
// MyDaoMaster helper = new MyDaoMaster(this, "androidframelearn.db"); //数据库升级写法 DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "androidframelearn.db"); //SQLiteDatabase db = helper.getWritableDatabase(); //不加密的写法 Database db = helper.getEncryptedWritableDb("aserbao"); //数据库加密密码为“aserbao"的写法 DaoMaster daoMaster = new DaoMaster(db); daoSession = daoMaster.newSession();
加密数据库的相关api同样可以参看greenDao上的官方文档,这里不再赘述。
4.7 插入数据
插入数据的操作跟Litepal类似:获取实体类对象,设置其属性,然后再通过greenDao中xyzDao提供的insert()
方法即可完成数据插入,代码如下:
private void insertDatabyGreenDao() { btn_db_insert.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mDaoSession != null){ Book book = new Book(); book.setName("The Da Vinci Code"); book.setAuthor("Dan Brown"); book.setPages(454); book.setPrice(16.96); mBookDao.insert(book); Log.i(TAG,"插入数据成功"); }else { Log.i(TAG,"插入数据失败"); } } }); }
插入数据后,我们点击查询数据(查询业务将在下一节提到),然后查看控制台,就可以查看到刚刚插入的数据,如图所示:
4.8 查询数据
查询数据的操作同样跟Litepal类似,只不过获取数据的方法变成了xyzDao下的loadAll()
,代码如下:
private void queryDatabyGreenDao() { btn_db_query.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mDaoSession != null){ List<Book> books = mBookDao.loadAll(); for (Book book : books){ Log.i(TAG,"查询数据成功"); Log.d("MainActivity","书名是"+book.getName()); Log.d("MainActivity","书的作者是"+book.getAuthor()); Log.d("MainActivity","书的页数是"+book.getPages()); Log.d("MainActivity","书的价格是"+book.getPrice()); } }else { Log.i(TAG,"查询数据失败"); } } }); }
相关的运行结果上一小节以贴出,这里不再重复。
4.9 更新数据
更新数据的操作同样和Litepal类似,只不过获取数据的方法变成了xyzDao下的update()
,代码如下:
btn_db_update.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mDaoSession != null){ Book book = new Book(); book.setId(0); book.setName("The Da Vinci Code"); book.setAuthor("Dan Brown"); book.setPages(100); book.setPrice(16.96); mBookDao.update(book); Log.i(TAG,"更新数据成功"); }else { Log.i(TAG,"更新数据失败"); } } });
更新数据后,我们再对数据进行查询,发现数据已有更新,如图所示:
4.10 删除数据
为了方便演示,删除数据直接使用了将所有数据都删除的deleteAll
,代码如下:
private void deleteDatabyGreenDao() { btn_db_delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mBookDao.deleteAll(); Log.i(TAG,"删除数据失败"); } }); }
当然,有关于CRUD的操作事实上还有很多的api,这里仅仅做一些简单的示范,详细的就如同前面所说的:参考官方文档,没有任何教程要比官方文档详细了。
5.源码地址
AFL——Android框架学习
更多相关文章
- Android性能优化-线程性能优化
- Android进程与线程基本知识二
- 常见ACTION的用法
- Android(安卓)Handler Message总结
- Android智能手机中各种音频场景下的audio data path
- Android目前流行三方数据库ORM分析及对比
- Android(安卓)Ap 开发 设计模式第五篇:单件模式
- Android下的配置管理之道之gerrit代码服务器搭建
- android 实现主线程、子线程双向通信