GreenDao 引入

GreenDao官网
GreenDaoAPI地址

GreenDao 3.3.0 基本使用与入门(一)
GreenDao 3.3.0 多表关联使用(二)
GreenDao 3.3.0 增删改查的使用(三)

Porject 目录下 build.gradle 下添加配置

    dependencies {        classpath 'com.android.tools.build:gradle:4.0.0'        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'//dagger2 apt 配置        classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0' //add plugin greendao配置         }

接下来在app的 build.gradle 中添加

apply plugin: 'org.greenrobot.greendao' // apply pluginandroid{    ...       greendao {        schemaVersion 5  //数据库版本号,升级数据库需要修改版本号        daoPackage 'com.greendao.dao'  //一般为app包名+生成文件的文件夹名        targetGenDir 'src/main/java'  //自动生成的greendao代码存放路径    }    }dependencies {    implementation fileTree(dir: "libs", include: ["*.jar"])    implementation 'androidx.appcompat:appcompat:1.1.0'    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'    implementation 'org.greenrobot:greendao:3.3.0' // add library    ....}

这样就完成GreenDao的引入了

Entity 注解详解

@Entity
表明这个实体类会在数据库中生成一个与之相对应的表
属性:

  • schema:告知GreenDao当前实体属于哪个 schema
  • schema active:标记一个实体处于活跃状态,活动实体有更新、删除和刷新方法
  • nameInDb:在数据库中使用的别名,默认使用的是实体的类名,
  • indexes:定义索引,可以跨越多个列
  • createInDb:标记创建数据库表(默认:true)
  • generateConstructors 自动创建全参构造方法(同时会生成一个无参构造方法)(默认:true)
  • generateGettersSetters 自动生成 getters and setters 方法(默认:true)
@Entity(        schema = "myschema",        active = true,        nameInDb = "AWESOME_USERS",        indexes = {                @Index(value = "name DESC", unique = true)        },        createInDb = true,        generateConstructors = false,        generateGettersSetters = true)public class User {  ...}

@Id
对应数据表中的 Id 字段

@Entitypublic class UserList {    @Id(autoincrement = true)//主键自动增长    private Long id;

@Index
使用@Index作为一个属性来创建一个索引,默认是使用字段名

@Entitypublic class User {    @Id     private Long id;    @Index(unique = true)    private String name;}

@OrderBy
更加某一字段排序 ,例如:@OrderBy(“date ASC”)

@OrderBy("date ASC")private List orders;

@Property
设置一个非默认关系映射所对应的列名,默认是使用字段名,例如:

@Entity (nameInDb = “User”)public class User {@Property(nameInDb = “userName”)private String userName;}

@NotNull
设置数据库表当前列不能为空

@Transient
添加此标记后不会生成数据库表的列

@Unique
表名该属性在数据库中只能有唯一值

@Entity public class User {@Id private Long id;@Unique private String name;}

注意事项

由于greenDAO 3.0 生成的字段添加了非空约束。字段的类型设置为基本类型(如:int)默认会添加非空约束,字段类型设置为对象类型(如:Integer)默认不会添加非空约束,而且最终生成的sql会使用对象类型

定义int类型

@Entitypublic class CommentList {    @Id(autoincrement = true)    private Long id;    private int sendId =0;//发送方ID    private int receiveId;//接收方ID    //------ CommentListDao.java  ------            /** Creates the underlying database table. */    public static void createTable(Database db, boolean ifNotExists) {        String constraint = ifNotExists? "IF NOT EXISTS ": "";        db.execSQL("CREATE TABLE " + constraint + "\"COMMENT_LIST\" (" + //                "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id                "\"SEND_ID\" INTEGER NOT NULL ," + // 1: sendId                "\"RECEIVE_ID\" INTEGER NOT NULL ," + // 2: receiveId                "\"SEND_TYPE\" INTEGER NOT NULL ," + // 3: sendType                

定义Integer类型

@Entitypublic class CommentList {    @Id(autoincrement = true)    private Long id;    private Integer sendId =0;//发送方ID    private Integer receiveId=0;//接收方ID    private Integer sendType=0;//发送方用户类型        // ------ CommentListDao.java  ------         /** Creates the underlying database table. */    public static void createTable(Database db, boolean ifNotExists) {        String constraint = ifNotExists? "IF NOT EXISTS ": "";        db.execSQL("CREATE TABLE " + constraint + "\"COMMENT_LIST\" (" + //                "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id                "\"SEND_ID\" INTEGER," + // 1: sendId                "\"RECEIVE_ID\" INTEGER," + // 2: receiveId                "\"SEND_TYPE\" INTEGER," + // 3: sendType                "\"RECEIVE_TYPE\" INTEGER," + // 4: receiveType

@Property 建表字段命名

使用@Entity建表的时候,默认情况下所有的表名和字段名都是大写的,使用nameInDb 定义表名和类名

@Entity(nameInDb ="User")public class User implements Serializable {    @Transient    private static final long serialVersionUID = 1L;    @Id(autoincrement = true )    private Long id;    @Property(nameInDb = "name")    private String name="Tom";    

GreenDao 3.3.0版本 设置默认值

默认GreenDao 是没有默认值得,网上说作者不屑于设置,网上搜索后,有很多是修改自动生成的xxxDao 里面的 createTable 中的建表SQL语句

    /** Creates the underlying database table. */    public static void createTable(Database db, boolean ifNotExists) {        String constraint = ifNotExists? "IF NOT EXISTS ": "";        db.execSQL("CREATE TABLE " + constraint + "\"USER\" (" + //                "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id                "\"NAME\" TEXT," + // 1: name                "\"AGE\" INTEGER NOT NULL ," + // 2: age                "\"SEX\" TEXT," + // 3: sex                "\"HEIGHT\" INTEGER NOT NULL ," + // 4: height                "\"WEIGHT\" TEXT);"); // 5: weight    }

也许由于版本的不同,反正3.3没有成功,Android Studio 执行Make Project后还原成原先建表语句,还有人说是修改实体类

@Entitypublic class User {    @Id(autoincrement = true)    private Long id;    private String name="Tom";    private int age=0;    private String sex;    private int height;    private String weight;    

这里有一个坑,这样的方式是可行的,但是如果你这里修改后,去观察UserDao中的建表语句,还是和之前一样是没有变化的.并没有带上 Default 默认值

这样修改后,在插入一条数据,不带默认值的字段赋值后查看数据表,就会发现默认值已经有了,但是UserDao的建表语句还是原来的

@Transient 注解

该注解用于当实体类中有字段不添加到数据表时使用

@Entitypublic class User implements Serializable {    @Transient    private static final long serialVersionUID = 1L;    @Id(autoincrement = true)    private Long id    

实体类实现 Serializable 报错

这个时候添加一行
@Transient
private static final long serialVersionUID = 1L;

DaoMaster DaoSession 数据操作和表管理

按照上面操作后Build> make project后再自动生成Dao的时候还会生成

  • DaoMaster 建表注册管理表
  • DaoSession 对表进行增删改查
public class GreenDBManager implements IDBManager {    private static final String DB_NAME = "User.db"; //数据库名    private DaoSession mDaoSession;    //private UserTableManager mUserTableManager;    private TablesComponent mTablesComponent;    private DaoMaster daoMaster;       public GreenDBManager init(Application application, String dbName) {        Integer dbVersion = DaoMaster.SCHEMA_VERSION;        mApplication = application;               Class<? extends AbstractDao<?, ?>>[] classes = new Class[]{UserDao.class, UserListDao.class};        //DBUpdateOpenHelper对DaoMaster进行初始化,这样就可以实现数据库升级时的数据迁移             DBUpdateOpenHelper updateOpenHelper = new DBUpdateOpenHelper(application, dbName, mclasses);        daoMaster = new DaoMaster(updateOpenHelper.getWritableDatabase());        //9.0的数据库默认启用了wal,用低版本的sqlite工具是无法查看的,想要兼容可以禁用wal        updateOpenHelper.getWritableDatabase().disableWriteAheadLogging();//启用 enableWriteAheadLogging        mDaoSession = daoMaster.newSession();        //查看数据库更新版本时数据迁移的log        MigrationHelper.DEBUG = false;        //数据库增删改查时的log        QueryBuilder.LOG_SQL = false;        QueryBuilder.LOG_VALUES = false;        //清空缓存        mDaoSession.clear();        return this;    }         @Override    public DaoSession getDaoSession() {        if (mDaoSession==null){            mDaoSession=daoMaster.newSession();        }        return mDaoSession;    }    

在Application 里面初始化init后,就可通过 getDaoSession 对所有表进行操作处理了

DBUpdateOpenHelper.java

public class DBUpdateOpenHelper extends DaoMaster.OpenHelper {    Class<? extends AbstractDao<?, ?>>[] mDaoClasses;    public DBUpdateOpenHelper(Context context, String name, Class<? extends AbstractDao<?, ?>>... daoClasses) {        super(context, name);        mDaoClasses=daoClasses;    }    public DBUpdateOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, Class<? extends AbstractDao<?, ?>>... daoClasses) {        super(context, name, factory);        mDaoClasses=daoClasses;    }    @Override    public void onCreate(Database db) {        DaoMaster.createAllTables(db, false);    }    @Override    public void onUpgrade(Database db, int oldVersion, int newVersion) {        //把需要管理的数据库表DAO作为最后一个参数传入到方法中        MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {            @Override            public void onCreateAllTables(Database db, boolean ifNotExists) {                DaoMaster.createAllTables(db, ifNotExists);            }            @Override            public void onDropAllTables(Database db, boolean ifExists) {                DaoMaster.dropAllTables(db, ifExists);            }        }, mDaoClasses);    }}

MigrationHelper.java 用于数据库升级时数据迁移

package com.zk.greendb.helper;import android.database.Cursor;import android.database.SQLException;import android.database.sqlite.SQLiteDatabase;import android.text.TextUtils;import android.util.Log;import org.greenrobot.greendao.AbstractDao;import org.greenrobot.greendao.database.Database;import org.greenrobot.greendao.database.StandardDatabase;import org.greenrobot.greendao.internal.DaoConfig;import java.lang.ref.WeakReference;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.Arrays;import java.util.List;/** * 用于数据库升级时数据迁移 * from https://github.com/yuweiguocn/GreenDaoUpgradeHelper * * please call {@link #migrate(SQLiteDatabase, Class[])} or {@link #migrate(Database, Class[])} */public class MigrationHelper {    public static boolean DEBUG = false;    private static final String TAG= MigrationHelper.class.getSimpleName();    private static final String SQLITE_MASTER = "sqlite_master";    private static final String SQLITE_TEMP_MASTER = "sqlite_temp_master";    private static WeakReference weakListener;    public interface ReCreateAllTableListener{        void onCreateAllTables(Database db, boolean ifNotExists);        void onDropAllTables(Database db, boolean ifExists);    }    public static void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {        printLog("【The Old Database Version】" + db.getVersion());        Database database = new StandardDatabase(db);        migrate(database, daoClasses);    }    public static void migrate(SQLiteDatabase db, MigrationHelper.ReCreateAllTableListener listener, Class<? extends AbstractDao<?, ?>>... daoClasses) {        weakListener = new WeakReference<>(listener);        migrate(db, daoClasses);    }    public static void migrate(Database database, MigrationHelper.ReCreateAllTableListener listener, Class<? extends AbstractDao<?, ?>>... daoClasses) {        weakListener = new WeakReference<>(listener);        migrate(database, daoClasses);    }    public static void migrate(Database database, Class<? extends AbstractDao<?, ?>>... daoClasses) {        printLog("【Generate temp table】start");        generateTempTables(database, daoClasses);        printLog("【Generate temp table】complete");        MigrationHelper.ReCreateAllTableListener listener = weakListener.get();        if (listener != null) {            listener.onDropAllTables(database, true);            printLog("【Drop all table by listener】");            listener.onCreateAllTables(database, false);            printLog("【Create all table by listener】");        } else {            dropAllTables(database, true, daoClasses);            createAllTables(database, false, daoClasses);        }        printLog("【Restore data】start");        restoreData(database, daoClasses);        printLog("【Restore data】complete");    }    private static void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {        for (int i = 0; i < daoClasses.length; i++) {            String tempTableName = null;            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);            String tableName = daoConfig.tablename;            if (!isTableExists(db, false, tableName)) {                printLog("【New Table】" + tableName);                continue;            }            try {                tempTableName = daoConfig.tablename.concat("_TEMP");                StringBuilder dropTableStringBuilder = new StringBuilder();                dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";");                db.execSQL(dropTableStringBuilder.toString());                StringBuilder insertTableStringBuilder = new StringBuilder();                insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName);                insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";");                db.execSQL(insertTableStringBuilder.toString());                printLog("【Table】" + tableName +"\n ---Columns-->"+getColumnsStr(daoConfig));                printLog("【Generate temp table】" + tempTableName);            } catch (SQLException e) {                Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e);            }        }    }    private static boolean isTableExists(Database db, boolean isTemp, String tableName) {        if (db == null || TextUtils.isEmpty(tableName)) {            return false;        }        String dbName = isTemp ? SQLITE_TEMP_MASTER : SQLITE_MASTER;        String sql = "SELECT COUNT(*) FROM " + dbName + " WHERE type = ? AND name = ?";        Cursor cursor=null;        int count = 0;        try {            cursor = db.rawQuery(sql, new String[]{"table", tableName});            if (cursor == null || !cursor.moveToFirst()) {                return false;            }            count = cursor.getInt(0);        } catch (Exception e) {            e.printStackTrace();        } finally {            if (cursor != null)                cursor.close();        }        return count > 0;    }    private static String getColumnsStr(DaoConfig daoConfig) {        if (daoConfig == null) {            return "no columns";        }        StringBuilder builder = new StringBuilder();        for (int i = 0; i < daoConfig.allColumns.length; i++) {            builder.append(daoConfig.allColumns[i]);            builder.append(",");        }        if (builder.length() > 0) {            builder.deleteCharAt(builder.length() - 1);        }        return builder.toString();    }    public static void dropAllTables(Database db, boolean ifExists, Class<? extends AbstractDao<?, ?>>... daoClasses) {        reflectMethod(db, "dropTable", ifExists, daoClasses);        printLog("【Drop all table by reflect】");    }    public static void createAllTables(Database db, boolean ifNotExists,  Class<? extends AbstractDao<?, ?>>... daoClasses) {        reflectMethod(db, "createTable", ifNotExists, daoClasses);        printLog("【Create all table by reflect】");    }    /**     * dao class already define the sql exec method, so just invoke it     */    private static void reflectMethod(Database db, String methodName, boolean isExists,  Class<? extends AbstractDao<?, ?>>... daoClasses) {        if (daoClasses.length < 1) {            return;        }        try {            for (Class cls : daoClasses) {                Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class);                method.invoke(null, db, isExists);            }        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }    private static void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {        for (int i = 0; i < daoClasses.length; i++) {            DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);            String tableName = daoConfig.tablename;            String tempTableName = daoConfig.tablename.concat("_TEMP");            if (!isTableExists(db, true, tempTableName)) {                continue;            }            try {                // get all columns from tempTable, take careful to use the columns list                List columns = getColumns(db, tempTableName);                ArrayList properties = new ArrayList<>(columns.size());                for (int j = 0; j < daoConfig.properties.length; j++) {                    String columnName = daoConfig.properties[j].columnName;                    if (columns.contains(columnName)) {                        properties.add(columnName);                    }                }                if (properties.size() > 0) {                    final String columnSQL = TextUtils.join(",", properties);                    StringBuilder insertTableStringBuilder = new StringBuilder();                    insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");                    insertTableStringBuilder.append(columnSQL);                    insertTableStringBuilder.append(") SELECT ");                    insertTableStringBuilder.append(columnSQL);                    insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");                    db.execSQL(insertTableStringBuilder.toString());                    printLog("【Restore data】 to " + tableName);                }                StringBuilder dropTableStringBuilder = new StringBuilder();                dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);                db.execSQL(dropTableStringBuilder.toString());                printLog("【Drop temp table】" + tempTableName);            } catch (SQLException e) {                Log.e(TAG, "【Failed to restore data from temp table 】" + tempTableName, e);            }        }    }    private static List getColumns(Database db, String tableName) {        List columns = null;        Cursor cursor = null;        try {            cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null);            if (null != cursor && cursor.getColumnCount() > 0) {                columns = Arrays.asList(cursor.getColumnNames());            }        } catch (Exception e) {            e.printStackTrace();        } finally {            if (cursor != null)                cursor.close();            if (null == columns)                columns = new ArrayList<>();        }        return columns;    }    private static void printLog(String info){        if(DEBUG){            Log.d(TAG, info);        }    }}

更多相关文章

  1. android 短信 彩信 数据库 转
  2. Android(安卓)TabWidget底部显示效果
  3. android 5.0系统主题颜色相关
  4. Android中自制通讯录中显示出数据库中的姓名和电话号码进行打电
  5. 方法数据库android轻量型数据库sqlite的使用方法汇总
  6. Android如何连接SQLServer数据库
  7. Android4.4.2配置修改记录
  8. Android(安卓)SQLiteOpenHelper的使用心得
  9. Android(安卓)USER 版本与ENG 版本的差异--MTK官方解释

随机推荐

  1. Android(安卓)7.0拍照权限处理
  2. android GestureListener
  3. Android中自定义标题栏(二)
  4. Android布局中添加条横线
  5. android 判断 无线是否可用
  6. 弹出NumberPicker窗口,修改字体大小
  7. Android(安卓)重启应用本身
  8. Building Local Unit Tests
  9. android 去home
  10. 第一行代码第三章源码整理