031-Android存储(6):GreenDao使用全解

674 阅读5分钟

【代码是最好的老师】

1.概述

GreenDAO 是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 框架

greendao具有以下优点,是项目架构期db方案的首选:

  1. 存取速度快
  2. 支持加密
  3. 轻量、api极简
  4. 支持缓存
  5. 中间代码自动生成,代码编写量小
  6. 【重点】开源至今,经历千锤百炼,稳定可靠

GitHub直达 GreenDao

2.使用

GreenDao3.3.0Demo.zip

总体分为三步:

  1. 配置导包
  2. 编写实体类(设计表)
  3. 编写CRUD工具类
  4. 调用封装的CRUD方法

本次采用得是组件化,使数据库有关的代码独立在一个module中,在APP module中调用。规范化开发,方便后续直接引入db_greendao库。

2.1 配置

step1、step2:

在项目根build.gradle中配置仓库源及插件

 //greendao_step1: add repository
 mavenCentral()
 
 //greendao_step2: add plugin
 classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0' 

如:

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        google()
        jcenter()
        //greendao_step1: add repository
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.0.2"
        classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0' //greendao_step2: add plugin
    }
}
allprojects {
    repositories {
        google()
        jcenter()
    }
}
task clean(type: Delete) {
    delete rootProject.buildDir
}

2.2 应用插件&导包

step3、step4、step5、step6:

gradle配置:应用插件、导包、配置greendao中间代码生成路径

//greendao_step3: apply plugin
apply plugin: 'org.greenrobot.greendao'

//greendao_step4: add library
implementation 'org.greenrobot:greendao:3.3.0' 

//greendao_step5:
//GreenDao 3.0+采用注解的方式来定义实体类,通过gradle插件生成相应的代码
greendao {
    schemaVersion 1
    daoPackage 'com.cupster.func_db_greendao.auto'//建议同一包名下
    targetGenDir 'src/main/java'
}

如:

apply plugin: 'com.android.application'
//greendao_step3:
apply plugin: 'org.greenrobot.greendao' 

android {
        ...
}
//greendao_step4:
//GreenDao 3.0+采用注解的方式来定义实体类,通过gradle插件生成相应的代码
greendao {
    schemaVersion 1
    daoPackage 'com.cupster.func_db_greendao.auto'//建议同一包名下
    targetGenDir 'src/main/java'
}
dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    //greendao_step5: add library
    implementation 'org.greenrobot:greendao:3.3.0' 
}

2.3 混淆

step6:

# greendao_step6:
# greendao 3.3.0 proguard
#======================================================================
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties { *; }

# If you DO use SQLCipher:
-keep class org.greenrobot.greendao.database.SqlCipherEncryptedHelper { *; }

# If you do NOT use SQLCipher:
-dontwarn net.sqlcipher.database.**
# If you do NOT use RxJava:
-dontwarn rx.**
#======================================================================

2.4 编写实体类(设计表)

step7:

编写实体类,根据需求加上响应注解,build project编译一下项目,就会自动生成中间代码。

在此之前需要简单了解一些基础的注解:

注解作用
@Entity声明当前实体类为greendao实体类,相当于数据库中的表
@Id@Id(autoincrement = true) 设置主键,自增长Id
@NotNull声明该字段在数据库不能为空 NOT NULL
@Entity
public class User {

    @Id(autoincrement = true)
    private Long _id;
    private int dr;
    private String headUrl;
    private String obj;

    @NotNull
    private String name;
    private String auth_token;
    @NotNull
    private String account;
    @NotNull
    private String password;

2.5编写DaoManager

step8:

build project之后,会在目标文件夹,生成DaoMaster、DaoSession、XxxDao中间代码。

其中的意义如下:

作用
DaoMasterDaoMaster保存数据库对象,代表着一个数据库的连接,内部有SQLiteOpenHelper实现
DaoSession为实体提供了一些通用的持久性方法,如CURD
XxxDAO[表名Dao]数据库表的访问对象,拥有基本的CURD及统计类等高级方法

使用之前,需要我们先编写DaoManager,封装数据库的创建、表创建、增删改查,以及数据库的升级等

//greendao_step8:编写dao管理类
public class DaoManager {
    private static final String TAG = "DaoManager";
    public static final String DB_NAME ="demo_db";
    public static boolean SHOW_LOG = false;

    private Context mContext;

    private volatile static DaoManager mDaoManager = null;
    private static DaoMaster mDaoMaster = null;
    private static DaoMaster.DevOpenHelper mDaoMasterHelper = null;
    private static DaoSession mDaoSession ;
    public static DaoManager getInstance(Context appContext){
        if (mDaoManager == null){
            mDaoManager = new DaoManager(appContext);
        }
        return  mDaoManager;
    }
    private DaoManager(Context context){
        mContext = context;
    }
    public DaoMaster getDaoMaster(){
        if (mDaoMaster == null){
            mDaoMasterHelper = new DaoMaster.DevOpenHelper(mContext ,DB_NAME ,null);
            mDaoMaster = new DaoMaster(mDaoMasterHelper.getWritableDb());
        }
        return mDaoMaster;
    }
    public DaoSession getDaoSession(){
        if (mDaoSession == null){
            if (mDaoMaster == null ){
                getDaoMaster();
            }
            mDaoSession = mDaoMaster.newSession();
        }
        return mDaoSession;
    }
    public void debug(){
        QueryBuilder.LOG_SQL = true;
        QueryBuilder.LOG_VALUES = true;
        SHOW_LOG = true;
    }
    public void closeConnection(){
        closeHelper();
        clearDaoSession();
    }
    private void closeHelper() {
        if (mDaoMasterHelper != null){
            mDaoMasterHelper.close();
            mDaoMasterHelper = null;
        }
    }
    private void clearDaoSession() {
        if (mDaoSession != null){
            mDaoSession.clear();
            mDaoSession = null;
        }
    }
}

2.6编写XxxDaoHelper

编写操作封装类XxxDaoHelper,用于完成具体的CRUD、count、条件查询操作、原始sql语句查询等

以用户表为例:

package com.cupster.func_db_greendao.crud;

import android.content.Context;
import android.util.Log;

import com.cupster.func_db_greendao.DaoManager;
import com.cupster.func_db_greendao.auto.UserDao;
import com.cupster.func_db_greendao.entity.User;

import org.greenrobot.greendao.query.QueryBuilder;

import java.util.List;

public class UserDaoHelper {

    private static final String TAG = "UserDaoHelper";
    private DaoManager mManager;

    public UserDaoHelper(Context appContext){
        mManager = DaoManager.getInstance( appContext );
    }

    /**
     * 单条插入
     * @param user
     * @return
     */
    public boolean insert(User user){
        boolean result = mManager.getDaoSession().getUserDao().insert(user) != -1;
        if (DaoManager.SHOW_LOG){
            Log.d(TAG, "insert: " + result +" ==> "+ user.toString());
        }
        return result;
    }

    /**
     * 多条item插入
     * @param userList
     * @return boolean结果
     */
    public boolean insertMulti(final List<User> userList){
        boolean result = false;
        try {
            mManager.getDaoSession().runInTx(new Runnable() {
                @Override
                public void run() {
                    for (User user : userList){
                       long add_id = mManager.getDaoSession().insertOrReplace(user) ;
                        if (DaoManager.SHOW_LOG){
                            Log.d(TAG, "insert items : " + add_id +" ==> "+ user.toString());
                        }
                    }
                }
            });
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }


    public boolean update(User user){
        boolean result = false;
        try {
            mManager.getDaoSession().update(user);
            result = true;
        }catch (Exception e){
            e.printStackTrace();
        }
        if (DaoManager.SHOW_LOG){
            Log.d(TAG, "update: " + result +" ==> "+ user.toString());
        }
        return result;
    }


    public boolean delete(User user){
        boolean result = false;
        try {
            mManager.getDaoSession().delete(user);
            result = true;
        }catch (Exception e ){e.printStackTrace();}
        if (DaoManager.SHOW_LOG){
            Log.d(TAG, "delete: " + result +" ==> "+ user.toString());
        }
        return result;
    }


    public boolean deleteAll(){
        boolean result = false;
        try {
            mManager.getDaoSession().deleteAll(User.class);
            result = true;
        }catch (Exception e ){
            e.printStackTrace();
        }
        if (DaoManager.SHOW_LOG){
            Log.d(TAG, "delete all : " + result );
        }
        return result;
    }

    public  List <User> queryAll (){
        return mManager.getDaoSession().loadAll(User.class);
    }

    public User queryById(long _id){
        return mManager.getDaoSession().load(User.class ,_id);
    }

    public List<User> queryBySQL(String sql , String[] conditions){
        return mManager.getDaoSession().queryRaw(User.class ,sql ,conditions);
    }

    /**
     * 使用queryBuilder 条件查询
     * @return
     */
    public List<User> queryByQueryBuilder(long id){
        QueryBuilder<User> queryBuilder = mManager.getDaoSession().queryBuilder(User.class);
        return queryBuilder.where(UserDao.Properties._id.eq(id)).list();
    }
    /**
     * 使用queryBuilder 条件查询
     * @return
     */
    public List<User> queryByQueryBuilder(String account){
        QueryBuilder<User> queryBuilder = mManager.getDaoSession().queryBuilder(User.class);
        return queryBuilder.where(UserDao.Properties.Account.eq(account)).list();
    }

    /**
     *
     * @param isDelete 0=false 1=true
     * @return
     */
    public List<User> queryByQueryBuilder(int isDelete){
        QueryBuilder<User> queryBuilder = mManager.getDaoSession().queryBuilder(User.class);
        return queryBuilder.where(UserDao.Properties.Dr.eq(isDelete)).list();
    }
}

至此,我们已经完成了具体表的操作封装。

3. 具体使用

实际结果:

初始代码:


    TextView mTvShow;
    UserDaoHelper mUserDaoHelper;
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_add_item).setOnClickListener(this);
        ...
    
        mTvShow = findViewById(R.id.tv_show);
        mUserDaoHelper = new UserDaoHelper(getApplicationContext());
    }

3.1增删改查-增 Insert

基于以上代码,进行单条数据插入:

    User user = new User();
    user.setAccount("18960222222");
    user.setName("Cupster");
    user.setPassword("Cupster@163.com");
    if (mUserDaoHelper.insert(user)){
        Toast.makeText(this ,"已添加",Toast.LENGTH_SHORT).show();
    }

list数据插入:

```java List list = new ArrayList<>(); User user1 = new User(); user1.setAccount("18960333333"); user1.setName("CupsterXX"); user1.setPassword("Cupster@163.com"); User user2 = new User(); user2.setAccount("18960444444"); user2.setName("Div"); user2.setDr(1); user2.setPassword("Cupster2@163.com"); User user3 = new User(); user3.setAccount("18960555555"); user3.setName("Higloo"); user3.setPassword("Cupster3@163.com"); list.add(user1); list.add(user2); list.add(user3); if (mUserDaoHelper.insertMulti(list)){ Toast.makeText(this ,"已添加",Toast.LENGTH_SHORT).show(); } ```

3.2增删改查-删 Delete

删除所有

                if (mUserDaoHelper.deleteAll()){
                    Toast.makeText(this ,"已删除",Toast.LENGTH_SHORT).show();
                }

删除指定数据

                User toDelelte =null;
                List <User> queryList = mUserDaoHelper.queryByQueryBuilder("18960222222");
                if (queryList != null && queryList.size() > 0 ){
                    toDelelte = queryList.get(0);
                    if (mUserDaoHelper.delete(toDelelte)){
                        Toast.makeText(this ,"已删除",Toast.LENGTH_SHORT).show();
                    }
                }else {
                    Toast.makeText(this ,"不存在or已删除",Toast.LENGTH_SHORT).show();
                }

3.3增删改查-改 Update

修改指定数据

                User toUpdate = null;
                List <User> queryList2 = mUserDaoHelper.queryByQueryBuilder("18960222222");
                if (queryList2 != null && queryList2.size() > 0 ){
                    toUpdate = queryList2.get(0);
                    toUpdate.setName(toUpdate.getName() +"[改]");
                }else {
                    toUpdate = new User();
                    toUpdate.setName("Xxx");
                    toUpdate.setAccount("133333333333");
                    toUpdate.setPassword("a123456");
                }
                if (mUserDaoHelper.update(toUpdate)){
                    Toast.makeText(this ,"已修改",Toast.LENGTH_SHORT).show();
                }

3.4增删改查-查 Query

查询所有:

                List<User> users = mUserDaoHelper.queryAll();
                StringBuilder strBuilder = new StringBuilder();
                for (User item : users) {
                    strBuilder.append("\n");
                    strBuilder.append(item.get_id());
                    strBuilder.append("\n");
                    strBuilder.append(item.getName());
                    strBuilder.append("\n");
                    strBuilder.append(item.getAccount());
                }
                mTvShow.setText(strBuilder.toString());

查询指定id:

                User userById = mUserDaoHelper.queryById(1);
                StringBuilder strBuilder1 = new StringBuilder();
                strBuilder1.append("\n");
                strBuilder1.append("查询id=0账户:");
                strBuilder1.append("\n");
                strBuilder1.append(userById.get_id());
                strBuilder1.append("\n");
                strBuilder1.append(userById.getName());
                strBuilder1.append("\n");
                strBuilder1.append(userById.getAccount());
                mTvShow.setText(strBuilder1.toString());

sql语句查询:

                String sql = "where _id > ?";
                String[] condition = new String[]{"0"};
                List<User> queryBySQL = mUserDaoHelper.queryBySQL(sql, condition);
                StringBuilder strBuilder2 = new StringBuilder();
                strBuilder2.append("\n");
                strBuilder2.append("查询id>0,账户:");
                for (User u : queryBySQL){
                    strBuilder2.append("\n");
                    strBuilder2.append(u.get_id());
                    strBuilder2.append("\n");
                    strBuilder2.append(u.getName());
                    strBuilder2.append("\n");
                    strBuilder2.append(u.getAccount());
                }
                mTvShow.setText(strBuilder2.toString());

条件查询:

List<User> userByWhereList = mUserDaoHelper.queryByQueryBuilder(1);
                StringBuilder strBuilder3 = new StringBuilder();
                strBuilder3.append("\n");
                strBuilder3.append("查询dr=1,假删除账户:");
                for (User u : userByWhereList){
                    strBuilder3.append("\n");
                    strBuilder3.append(u.get_id());
                    strBuilder3.append("\n");
                    strBuilder3.append(u.getName());
                    strBuilder3.append("\n");
                    strBuilder3.append(u.getAccount());
                }
                mTvShow.setText(strBuilder3.toString());

4.总结

至此,从配置到增删改查已简述完毕,具体代码请参考:

GreenDao3.3.0Demo.zip

Gitee: GreenDao3.3.0Demo