Android greenDAO3x数据库框架使用小结

来源:互联网 发布:剑三捏脸数据成男下载 编辑:程序博客网 时间:2024/05/21 17:19
greenDAO是个很好用的Android数据库框架

https://github.com/greenrobot/greenDAO


导入工程

在Project目录的build.gradle文件中添加

buildscript {    repositories {        mavenCentral()    }    dependencies {        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.0'    }}

在Module目录中的build.gradle文件中添加

apply plugin: 'org.greenrobot.greendao'dependencies {    compile 'org.greenrobot:greendao:3.2.0'}

完成上述动作后,接着给项目配置自动生成创建db代码文件的相关参数。
在Module中配置build.gradle参数

defaultConfig {        applicationId "demo.app.android.greendao3xdemo"        versionCode 1    }greendao {    schemaVersion 1    daoPackage 'demo.app.android.greendao3xdemo.db'    targetGenDir 'src/main/java'}


创建表对应实体类和简单的crud

greenDAO 2.x需要创建一个java项目来自动生成表对应的实体类,而3.x可以通过注解的方式来自动生成对应的实体类。
到目前为止,2.x和3.x的生成方式各有优缺点。3.x自动生成的实体类使用起来比2.x便捷,2.x的可以定制内容不同的数据库(多Schema)
不过个人感觉3.x还是比2.x好用很多


一般常见应用中都有用户模块,那么这里创建一个User类演示

package demo.app.android.greendao3xdemo.db.model;@Entitypublic class User {    @Id private Long id;    @Property(nameInDb = "USERNAME") private String username;}

@Entity 建立表和实体的对应关系
@Id 建立表主键和类成员变量关系
@Property 建立表字段和类成员变量关系

之后Build Moudle,会自动生成构造方法、get、set等


此刻Moudle中应该会产生类似如下的目录结构




在具体数据的crud之前,应该预先在全局的applicaiton对象中准备好数据库session对象

public class App extends Application {    private static App instance;    private DaoMaster.OpenHelper dbHelper;    private DaoSession dbSession;    @Override    public void onCreate() {        super.onCreate();        instance = this;    }    public static synchronized App i() {        return instance;    }    public DaoSession getDBSession() {        if (dbSession != null) {            dbSession.clear();        }        if (dbHelper == null) {            dbHelper = new DaoMaster.DevOpenHelper(this, "db_user");            DaoMaster daoMaster = new DaoMaster(dbHelper.getWritableDatabase());            dbSession = daoMaster.newSession();        }        return dbSession;    }}


在一切都准备就绪后便可以开始实战。
添加登录界面并且加入登录逻辑(并且将用户保存至数据库)



简单的保存动作

String sUsername = eUsername.getText().toString().trim();UserDao userDao = App.i().getDBSession().getUserDao();User user = new User();user.setId(System.currentTimeMillis());user.setUsername(sUsername);userDao.insertOrReplace(user);

那么实际上,user的数据应用一般会用于各个界面,有必要将user作为成员保留在application对象中

public class App extends Application {    public void setCurrUser(User user) {        UserDao userDao = getDBSession().getUserDao();        userDao.insertOrReplace(user);        currUser = user;        // 保存上一次的登录者id至SharedPreferences        Utils.spWrite("last_login_user_id", currUser.getId());    }    public User getCurrUser() {        if (currUser == null) {            long lastLoginUserId = Utils.spReadLong("last_login_user_id", 0);            if (lastLoginUserId > 0) {                UserDao userDao = getDBSession().getUserDao();                currUser = userDao.queryBuilder().where(UserDao.Properties.Id.eq(lastLoginUserId)).unique();            }        }        return currUser;    }}

多用户数据库之间的切换

支持多用户登录在app中也是一种常态。那么在构建数据库的时候使用"一个用户对应一个库的策略方案"会有很多优势。

例如 添加新功能 用户可以创建的日记便签
表NOTE 字段 CONTENT
如果所有用户使用同一个数据库 
这里将必然添加新字段USER_ID之类的来建立日记便签与用户之间的关联关系,并且在查询数据的时候都必须添加'WHERE USER_ID = ' 之类的条件。
如果使用"一个用户对应一个库的策略方案",由于这个当前库的数据全部都是该用户的,查询效率提高的同时,代码书写也将简化。
那么就需要在用户切换账号登录的同时,程序里需要切换数据库。

public class App extends Application {    private static App instance;    private DaoMaster.OpenHelper dbHelper;    private DaoSession dbSession;    private User currUser;    @Override    public void onCreate() {        super.onCreate();        instance = this;    }    public static synchronized App i() {        return instance;    }    public DaoSession getCurrDBSession() {        getCurrUser();        return getDBSession(currUser.getId());    }    private DaoSession getDBSession(long id) {        if (dbSession != null) {            dbSession.clear();        }        if (dbHelper != null &&                (currUser == null || currUser.getId() != id)) {            dbHelper.close();            dbHelper = null;        }        if (dbHelper == null) {            dbHelper = new DaoMaster.DevOpenHelper(this, "db_user_" + id);            DaoMaster daoMaster = new DaoMaster(dbHelper.getWritableDatabase());            dbSession = daoMaster.newSession();        }        return dbSession;    }    public void setCurrUser(User user) {        if (user == null) {            if (dbSession != null) {                dbSession.clear();            }            if (dbHelper != null) {                dbHelper.close();                dbHelper = null;            }            currUser = null;            Utils.spWrite("last_login_user_id", 0);        } else {            UserDao userDao = getDBSession(user.getId()).getUserDao();            userDao.insertOrReplace(user);            currUser = user;            // 保存上一次的登录者id至SharedPreferences            Utils.spWrite("last_login_user_id", currUser.getId());        }    }    public User getCurrUser() {        if (currUser == null) {            long lastLoginUserId = Utils.spReadLong("last_login_user_id", 0);            if (lastLoginUserId > 0) {                UserDao userDao = getDBSession(lastLoginUserId).getUserDao();                currUser = userDao.queryBuilder().where(UserDao.Properties.Id.eq(lastLoginUserId)).unique();            }        }        return currUser;    }}

之后只需要在登录或者切换的时候调用
App.i().setCurrUser()
在全局任意位置需要获得User信息的时候调用
App.i().getCurrUser()


数据库版本升级

版本发布上架后,下一个版本需要添加新功能给用户设置头像
那么首先

@Entitypublic class User {    @Id private Long id;    @Property(nameInDb = "USERNAME") private String username;    @Property(nameInDb = "AVATAR") private String avatar;}

defaultConfig {        applicationId "demo.app.android.greendao3xdemo"        versionCode 2    }greendao {    schemaVersion 2    daoPackage 'demo.app.android.greendao3xdemo.db'    targetGenDir 'src/main/java'}

重新Build项目

将这里的schemaVersion改为2后在dbHelper.getWritableDatabase()时刻满足一定条件下会触发onUpgrade方法。此时可以重写OpenHelper#onUpgrade方法更新数据库结构等
以上使用了DaoMaster.DevOpenHelper,而其中逻辑实现为

  dropAllTables(db, true);  onCreate(db);
这样的话,之前版本数据都会丢失。

创建支持升级的OpenHelper

package demo.app.android.greendao3xdemo.db.upgrade;public class UpgradeableOpenHelper extends DaoMaster.OpenHelper {    public UpgradeableOpenHelper(Context context, String name) {        super(context, name);    }    @Override    public void onUpgrade(Database db, int oldVersion, int newVersion) {        Utils.logd("greenDAO Upgrading schema from version %d to %d", oldVersion, newVersion);        if (oldVersion == 1 && newVersion == 2) {            final long alterDate = System.currentTimeMillis();            // step 1 将表名改为临时表            db.execSQL("ALTER TABLE \"USER\" RENAME TO \"_USER_old_" + alterDate + "\"");            // step 2 创建新表            UserDao.createTable(db, false);            // step 3 导入数据            final String oldC = "_id, USERNAME";            final String newC = oldC;            db.execSQL("INSERT INTO \"USER\" (" + newC + ") SELECT " + oldC + " FROM \"_USER_old_" + alterDate + "\"");            // step 4 删除临时表            db.execSQL("DROP TABLE \"_USER_old_" + alterDate + "\"");        }    }}

if (dbHelper == null) {            dbHelper = new UpgradeableOpenHelper(this, "db_user_" + id);            DaoMaster daoMaster = new DaoMaster(dbHelper.getWritableDatabase());            dbSession = daoMaster.newSession();        }

随着应用日渐更新,必然的之后将会出现版本3,4,5...
那么这里有必要对UpgradeableOpenHelper的代码进一步优化

public class UpgradeableOpenHelper extends DaoMaster.OpenHelper {    public UpgradeableOpenHelper(Context context, String name) {        super(context, name);    }    @Override    public void onUpgrade(Database db, int oldVersion, int newVersion) {        Utils.logd("greenDAO Upgrading schema from version %d to %d", oldVersion, newVersion);        for (int i = oldVersion; i < newVersion; i++) {            try {                AbstractDBMigratorHelper migratorHelper =                        (AbstractDBMigratorHelper) Class.forName(                                AbstractDBMigratorHelper.UPGRADE_PACKAGE_NAME + ".DBMigrationHelper" + (i + 1)).newInstance();                if (migratorHelper != null) {                    migratorHelper.onUpgrade(db);                }            } catch (Exception e) {                e.printStackTrace();                Utils.loge("greenDAO Could not migrate from schema from schema: %d to %d", i, i + 1);                break;            }        }    }}

package demo.app.android.greendao3xdemo.db.upgrade;import org.greenrobot.greendao.database.Database;import java.util.Date;public abstract class AbstractDBMigratorHelper {    public static final String UPGRADE_PACKAGE_NAME = "demo.app.android.greendao3xdemo.db.upgrade";    public abstract void onUpgrade(Database db);    public static final void createTemporaryTable(Database db, String tableName, Date createDate) {        final String ALTER_TABLE_RENAME = "ALTER TABLE \"%s\" RENAME TO \"_%s_old_%ts\"";        db.execSQL(String.format(ALTER_TABLE_RENAME, tableName, tableName, createDate));    }    public static final void dataTransferFromTemporary(Database db, String tableName, Date tempDate, String oldC, String newC) {        final String DATA_TRANSFER = "INSERT INTO \"%s\" (%s) SELECT %s FROM \"_%s_old_%ts\"";        db.execSQL(String.format(DATA_TRANSFER, tableName, newC, oldC, tableName, tempDate));    }    public static final void dropTemporaryTable(Database db, String tableName, Date createDate) {        final String DROP_TABLE = "DROP TABLE \"_%s_old_%ts\"";        db.execSQL(String.format(DROP_TABLE, tableName, createDate));    }}


利用Class.forName("").newInstance()和递归机制 将数据库迭代升级的逻辑转移至DBMigrationHelper中
例如刚才的version1升级到version2的逻辑可以简化为

public class DBMigrationHelper2 extends AbstractDBMigratorHelper {    @Override    public void onUpgrade(Database db) {        Date alterDate = new Date();        // step 1 将表名改为临时表        createTemporaryTable(db, UserDao.TABLENAME, alterDate);        // step 2 创建新表        UserDao.createTable(db, false);        // step 3 导入数据        final String oldC = "_id, USERNAME";        final String newC = oldC;        dataTransferFromTemporary(db, UserDao.TABLENAME, alterDate, oldC, newC);        // step 4 删除临时表        dropTemporaryTable(db, UserDao.TABLENAME, alterDate);    }}

数据库内容加密

http://greenrobot.org/greendao/documentation/database-encryption/



混淆规则 引用自‘http://www.jianshu.com/p/cb4d346d7e2a’

### greenDAO 3-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {public static java.lang.String TABLENAME;}-keep class **$Properties# If you do not use SQLCipher:-dontwarn org.greenrobot.greendao.database.**# If you do not use RxJava:-dontwarn rx.**### greenDAO 2-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {public static java.lang.String TABLENAME;}-keep class **$Properties
-keep class com.cn.daqi.otv.db.*{ *; } (实体类所在的包)

3 0
原创粉丝点击