文章目录

  • 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要复杂些,正因如此,它的功能也更加强大。它的主要特性如下:

  1. 高性能,下面是官方给出的关于GreenDao,OrmLite和ActiveAndroid三种ORM解决方案的数据统计图:

  2. 易于使用的强大API,涵盖关系和连接;

  3. 最小的内存消耗;

  4. 占用内存小(<100KB)以保持较低的构建时间并避免65k方法限制;

  5. 数据库加密: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操作之前,我们简单提及一下数据库相关的方法。

一般来说,如果只是简单地进行升级,步骤大抵如下:

  1. 在module的build.gradle文件中升级版本号,即schemaVersion
  2. 修改实体类
  3. 重新编译项目即可

而稍微复杂一些的数据库升级情况,例如数据库迁移等,greenDao的OpenHelper下有个 onUpgrade(Database db, int oldVersion, int newVersion)方法,当设置的数据库版本改变时,在数据库初始化的时候就会回调到这个方法,我们可以通过继承OpenHelper重写onUpgrade方法来实现数据库更新操作,步骤大抵如下:

  1. 创建临时表TMP_,复制原来的数据库到临时表中;
  2. 删除之前的原表;
  3. 创建新表;
  4. 将临时表中的数据复制到新表中,最后将TMP_表删除掉;

升级数据库的操作建议参看greenDao上的官方文档(作者本地被墙,没法上网查看),这里不再赘述。

4.6 加密数据库

开发中对于存储于数据库中的敏感数据,我们可以通过对数据库加密来进行保护。greenDao可以通过SQLCipher来进行加密处理。下面我们简单讲解下加密过程:

步骤:

  1. 导入加密库文件依赖:
implementation 'net.zetetic:android-database-sqlcipher:3.5.6'
  1. 修改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框架学习

更多相关文章

  1. Android性能优化-线程性能优化
  2. Android进程与线程基本知识二
  3. 常见ACTION的用法
  4. Android(安卓)Handler Message总结
  5. Android智能手机中各种音频场景下的audio data path
  6. Android目前流行三方数据库ORM分析及对比
  7. Android(安卓)Ap 开发 设计模式第五篇:单件模式
  8. Android下的配置管理之道之gerrit代码服务器搭建
  9. android 实现主线程、子线程双向通信

随机推荐

  1. 选择器的优先级,id,class,tag
  2. 十年软件测试感悟
  3. 2021春招 ,百度,阿里,美团等大厂全新PHP面试
  4. HTML中表格和表单的应用实例 (MD)
  5. CSS选择器优先级、模块化与伪类选择器的
  6. 学web前端有什么计划?
  7. NA公链(Nirvana)NAC公链独步公链江湖
  8. 助力你的年度大戏:“金三银四”的折腾
  9. “金三银四”的折腾之聊一聊面试
  10. 高效、易用、功能强大的 api 管理平台