小言_互联网的博客

每天学习一个Android中的常用框架——2.greenDao

404人阅读  评论(0)

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 plugin

android {
    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方法,代码如下:

@Entity
public 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;

@Entity
public 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框架学习


转载:https://blog.csdn.net/qq_41151659/article/details/105923497
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场