1. 概述
在android开发中,可能或多或少的都会接触 Sqlite数据库,然而我们在使用它的时候通常需要做很多的额外工作,比如就像编写 Sqlite语句、解析查询结果等等,所以适用于Android的 ORM框架 横空出世,现在市面上边主流的框架有 Sqlite、LitePal、GreenDao、Realm、OrmLite、SugarORM、Active Android,而 GreenDao号称是速度最快的 ORM框架,在使用之前需要配置一些地方,那么接下来我们就来看下它的具体配置及时如何使用的。
ORM还不是很清楚的,可以看下我之前的文章 第三方数据库框架 - LitePal简介
2. 需要配置的地方
2.1>:project下的build.gradle
2.2>:app下的 build.gradle,这里需要配置3个地方
需要注意下边配置的地方:
/*targetGenDirTest:设置生成单元测试目录
generateTests:设置自动生成单元测试用例*/
schemaVersion 1 // 数据库schema版本,也就是数据库的版本号
daoPackage 'cn.novate.greendao.greendao' // DaoMaster、DaoSession、UserDao所在的包名
targetGenDir 'src/main/java' // DaoMaster、DaoSession、UserDao所在的目录
以上就已经配置好了,然后点击 Sync Now,就是立即构建,就会在 cn.novate.greendao包下边生成 DaoMaster、DaoSession、UserDao这3个类,注意这3个类都是 在 上边自己配置的cn.novate.greendao.greendao包下边,接下来就是具体使用了。
3. 具体使用
3.1>: 写一个JavaBean,也就是我们的 User 实体类对象,就是我们数据库中的表;
/**
* Email: [email protected]
* Created by JackChen 2018/4/11 9:07
* Version 1.0
* Params:
* Description:
*/
/**
* @Entity: 将我们普通的java类变为一个能够被 greendao 识别的数据库类型的实体类
* @Id: 通过 @Id 注解 标记的字段必须是 Long类型的,注意是包装类型的,这个字段在数据库中表示它就是主键,并且默认是自增的
* @NotNul: 数据库的表当前的列不能为空
*/
@Entity
public class User {
@Id
private Long id ;
private String name ;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@Generated(hash = 873297011)
public User(Long id, String name) {
this.id = id;
this.name = name;
}
@Generated(hash = 586692638)
public User() {
}
}
3.2>:然后点击 build下边的 Make Project,然后就会发现自己的 User实体类中多了好多代码,没错,这个就是 GreenDao给我们自动生成的
需要注意:
第一:如果你想再次添加实体类Age,可以直接写一个实体类Age,然后点击 Build下的 Make Project会重新为你生成AgeDao;
第二:不要手动修改DaoMaster、DaoSession、UseDao和User中的代码,因为每一次编译项目的时候,都会重新生成一次DaoMaster、DaoSession、UserDao和User,所以说如果修改了的话就会被覆盖;
3.3>:为了便于数据的读取和添加,这里新建GreenDaoHelper,用于获取DaoMaster、DaoSession,代码如下:
* Email: [email protected]
* Created by JackChen 2018/4/11 13:18
* Version 1.0
* Params:
* Description: 便于数据的读取和添加,新建GreenDaoHelper辅助类
*/
public class GreenDaoHelper extends Application {
private GreenDaoHelper Instance;
private static DaoMaster daoMaster;
private static DaoSession daoSession;
public GreenDaoHelper getInstance() {
if (Instance == null) {
Instance = this;
}
return Instance;
}
/**
* 获取DaoMaster
*
* @param context
* @return
*/
public static DaoMaster getDaoMaster(Context context) {
if (daoMaster == null) {
try{
DaoMaster.OpenHelper helper = new DaoMaster.DevOpenHelper(context,"test.db",null);
daoMaster = new DaoMaster(helper.getWritableDatabase()); //获取未加密的数据库
}catch (Exception e){
e.printStackTrace();
}
}
return daoMaster;
}
/**
* 获取DaoSession对象
*
* @param context
* @return
*/
public static DaoSession getDaoSession(Context context) {
if (daoSession == null) {
if (daoMaster == null) {
getDaoMaster(context);
}
daoSession = daoMaster.newSession();
}
return daoSession;
}
}
需要注意:
到这里就已经创建好User实体类,并且也可以直接获取 DaoMaster、DaoSession对象,接下来就可以进行增删改查操作了。
4. 添加数据和查询
4.1>:添加数据
第一:创建User对象,然后设置数据,参数一是id,Long包装类型的,参数二是name,传递时候传递的是null目的就是在插入的过程中,id会自增长,
第二:调用 UserDao的 insert方法,用于添加数据;
具体代码如下:
public class MainActivity extends AppCompatActivity {
private DaoSession daoSession;
private TextView textview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化权限
initPermission();
textview = (TextView) findViewById(R.id.textview);
daoSession = GreenDaoHelper.getDaoSession(this);
daoSession.getUserDao().deleteAll(); // 清空所有记录
// 添加数据
// 参数1:id 传递null表示
User user = new User(null , "王子文") ;
User user1 = new User(null , "北京-Novate") ;
daoSession.getUserDao().insert(user) ;
daoSession.getUserDao().insert(user1) ;
// 查询数据
StringBuilder sb = new StringBuilder() ;
List users = daoSession.getUserDao().loadAll() ;
for (int i = 0; i < users.size(); i++) {
sb.append("id: ").append(users.get(i).getId()).
append(", name: ").append(users.get(i).getName()).append("\n") ;
}
textview.setText(sb);
}
/**
* 初始化权限事件
*/
private void initPermission() {
//检查权限
String[] permissions = CheckPermissionUtils.checkPermission(this);
if (permissions.length == 0) {
//权限都申请了
//是否登录
} else {
//申请权限
ActivityCompat.requestPermissions(this, permissions, 100);
}
}
}
运行结果如下:
5. 修改存放数据库路径
一般情况下,新建的数据库默认位置是存放在 data/data/包名/database下边的,手机如果不root的话,根本就无法查看 test.db数据库文件,更别提想要去操作该 test.db数据库文件。而在实际的开发过程中,可能需要copy数据库,或者使用第三方工具打开 该 test.db数据库文件来查看里边的数据,此时可以通过重写 Context的 getDatabasePath()、openOrCreateDatabase()、openOrCreateDatabase()这3个方法来修改 test.db的数据库文件的存放路径。
// 方法一
getDatabasePath(String name)
// 方法二
openOrCreateDatabase(String name, int mode, CursorFactory factory)
// 方法三
openOrCreateDatabase(String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler)
上边已经说了,DaoMaster中的代码是不能修改的,所以我们可以把重写的方法 放到 GreenDaoHelper中即可,具体代码如下:
public class GreenDaoHelper extends Application {
private GreenDaoHelper Instance;
private static DaoMaster daoMaster;
private static DaoSession daoSession;
public GreenDaoHelper getInstance() {
if (Instance == null) {
Instance = this;
}
return Instance;
}
/**
* 获取DaoMaster
*
* @param context
* @return
*/
public static DaoMaster getDaoMaster(Context context) {
if (daoMaster == null) {
try{
ContextWrapper wrapper = new ContextWrapper(context) {
/**
* 获得数据库路径,如果不存在,则创建对象对象
*
* @param name
*/
@Override
public File getDatabasePath(String name) {
// 判断是否存在sd卡
boolean sdExist = android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState());
if (!sdExist) {// 如果不存在,
Log.e("SD卡管理:", "SD卡不存在,请加载SD卡");
return null;
} else {// 如果存在
// 获取sd卡路径
String dbDir = android.os.Environment.getExternalStorageDirectory().getAbsolutePath();
dbDir += "/Android";// 数据库所在目录
String dbPath = dbDir + "/" + name;// 数据库路径
// 判断目录是否存在,不存在则创建该目录
File dirFile = new File(dbDir);
if (!dirFile.exists())
dirFile.mkdirs();
// 数据库文件是否创建成功
boolean isFileCreateSuccess = false;
// 判断文件是否存在,不存在则创建该文件
File dbFile = new File(dbPath);
if (!dbFile.exists()) {
try {
isFileCreateSuccess = dbFile.createNewFile();// 创建文件
} catch (IOException e) {
e.printStackTrace();
}
} else
isFileCreateSuccess = true;
// 返回数据库文件对象
if (isFileCreateSuccess)
return dbFile;
else
return super.getDatabasePath(name);
}
}
/**
* 重载这个方法,是用来打开SD卡上的数据库的,android 2.3及以下会调用这个方法。
*
* @param name
* @param mode
* @param factory
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
}
/**
* Android 4.0会调用此方法获取数据库。
*
* @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String,
* int,
* android.database.sqlite.SQLiteDatabase.CursorFactory,
* android.database.DatabaseErrorHandler)
* @param name
* @param mode
* @param factory
* @param errorHandler
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
}
};
DaoMaster.OpenHelper helper = new DaoMaster.DevOpenHelper(wrapper,"test.db",null);
daoMaster = new DaoMaster(helper.getWritableDatabase()); //获取未加密的数据库
}catch (Exception e){
e.printStackTrace();
}
}
return daoMaster;
}
/**
* 获取DaoSession对象
*
* @param context
* @return
*/
public static DaoSession getDaoSession(Context context) {
if (daoSession == null) {
if (daoMaster == null) {
getDaoMaster(context);
}
daoSession = daoMaster.newSession();
}
return daoSession;
}
}
通过上边修改后的 GreenDaoHelper的代码后,我们可以在 手机存储 --> Android --> 里边就会有 test.db数据库文件,不清楚自己创建的 test.db数据库文件存放路径在哪,可以看下边我的手机截图:
然后可以通过 qq或者微信 发送到电脑桌面,通过第三方工具打开该 test.db数据库文件,就可以看到自己在代码中写的User对象实体类对应的 --> USER表及该表中的字段如下图所示:
当然也可以使用 手机查看,都是可以的。
6. 数据库加密
可以直接调用 DaoMaster.OpenHelper()的getEncryptedWritableDb(password)或者getEncryptedReadableDb(password)方法即可,就可以对获取一个加密的数据库;
public static DaoMaster getDaoMaster(Context context) {
if (daoMaster == null) {
try{
ContextWrapper wrapper = new ContextWrapper(context) {
...
};
DaoMaster.OpenHelper helper = new DaoMaster.DevOpenHelper(wrapper,"test.db",null);
daoMaster = new DaoMaster(helper.getEncryptedWritableDb("1234"));//获取加密的数据库
//daoMaster = new DaoMaster(helper.getEncryptedReadableDb("1234"));//获取加密的数据库
//daoMaster = new DaoMaster(helper.getWritableDatabase()); //获取未加密的数据库
}catch (Exception e){
e.printStackTrace();
}
}
return daoMaster;
}
若要解密或重新加密数据库,可参考博客《利用SQLCipher加解密数据库(包括加解密已有的数据库)》。
7. 数据库升级但又不删除数据
使用DevOpenHelper升级数据库时,表都会删除重建。因此,在实际开发过程中都是在 GreenDaoHelper中自己写一个类继承 DaoMaster.OpenHelper实现 onUpdate()方法,使得数据库升级。我们示例代码中是这样做的:
7.1>:复制 MigrationHelper类到项目中;
7.2>:然后在 GreenDaoHelper中自定义MySQLiteOpenHelper继承 DaoMaster.OpenHelper,实现 onUpdate()方法;代码如下:
public class GreenDaoHelper extends Application {
private GreenDaoHelper Instance;
private static DaoMaster daoMaster;
private static DaoSession daoSession;
public GreenDaoHelper getInstance() {
if (Instance == null) {
Instance = this;
}
return Instance;
}
/**
* 获取DaoMaster
*
* @param context
* @return
*/
public static DaoMaster getDaoMaster(Context context) {
if (daoMaster == null) {
try{
ContextWrapper wrapper = new ContextWrapper(context) {
...
};
DaoMaster.OpenHelper helper = new MySQLiteOpenHelper(wrapper,"test.db",null);
//daoMaster = new DaoMaster(helper.getEncryptedWritableDb("1234"));//获取加密的数据库
//daoMaster = new DaoMaster(helper.getEncryptedReadableDb("1234"));//获取加密的数据库
daoMaster = new DaoMaster(helper.getWritableDatabase()); //获取未加密的数据库
}catch (Exception e){
e.printStackTrace();
}
}
return daoMaster;
}
/**
* 获取DaoSession对象
*
* @param context
* @return
*/
public static DaoSession getDaoSession(Context context) {
if (daoSession == null) {
if (daoMaster == null) {
getDaoMaster(context);
}
daoSession = daoMaster.newSession();
}
return daoSession;
}
private static class MySQLiteOpenHelper extends DaoMaster.OpenHelper {
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
private static final String UPGRADE="upgrade";
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
MigrationHelper.migrate(db,AreaDao.class);
Log.e(UPGRADE,"upgrade run success");
}
}
}
7.3>:然后新建一个 People实体类类,自己只需要写下边代码即可,然后直接 build --> Make Model app就会生成下边的代码;
@Entity
public class People {
@Id
private Long id ;
private String Name ;
private String Sex ;
}
@Entity
public class People {
@Id
private Long id ;
private String Name ;
private String Sex ;
public String getSex() {
return this.Sex;
}
public void setSex(String Sex) {
this.Sex = Sex;
}
public String getName() {
return this.Name;
}
public void setName(String Name) {
this.Name = Name;
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@Generated(hash = 1284135911)
public People(Long id, String Name, String Sex) {
this.id = id;
this.Name = Name;
this.Sex = Sex;
}
@Generated(hash = 1406030881)
public People() {
}
}
7.4>:修改 schemaVersion 版本号为更高的;
7.5>:然后修改 onUpdate()方法如下:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
MigrationHelper.migrate(db,AreaDao.class, PeopleDao.class);
Log.e(UPGRADE,"upgrade run success");
}
然后运行程序,发现会报如下的错,意思就是找不到People这张表:
通过阅读源码发现,程序会根据传入的 beanDao会对所有的 JavaBean创建临时表, 然后把 该 JavaBean表中的数据 复制到 bean_temp临时表中,但是这个时候 People实体类是新创建的,数据库中并没有这个表,所以会报上边的错误,所以我们只需要对源码稍作修改,让它只对数据库中已有的表创建临时表并且保存数据,还有,源码中是按照字段恢复数据,我们把它修改为全表查询恢复;
代码如下:
public final class MigrationHelper {
public static boolean DEBUG = false;
private static String TAG = "MigrationHelper";
private static List tablenames = new ArrayList<>();
public static List getTables(SQLiteDatabase db){
List tables = new ArrayList<>();
Cursor cursor = db.rawQuery("select name from sqlite_master where type='table' order by name", null);
while(cursor.moveToNext()){
//遍历出表名
tables.add(cursor.getString(0));
}
cursor.close();
return tables;
}
public static void migrate(SQLiteDatabase db, Class extends AbstractDao, ?>>... daoClasses) {
Database database = new StandardDatabase(db);
if (DEBUG) {
Log.d(TAG, "【Database Version】" + db.getVersion());
Log.d(TAG, "【Generate temp table】start");
}
tablenames=getTables(db);
generateTempTables(database, daoClasses);
if (DEBUG) {
Log.d(TAG, "【Generate temp table】complete");
}
dropAllTables(database, true, daoClasses);
createAllTables(database, false, daoClasses);
if (DEBUG) {
Log.d(TAG, "【Restore data】start");
}
restoreData(database, daoClasses);
if (DEBUG) {
Log.d(TAG, "【Restore data】complete");
}
}
private static void generateTempTables(Database db, Class extends AbstractDao, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
String tempTableName = null;
try {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
if(!tablenames.contains(daoConfig.tablename)){//如果数据库中没有该表,则继续下次循环
continue;
}
String tableName = daoConfig.tablename;
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());
if (DEBUG) {
Log.d(TAG, "【Table】" + tableName +"\n ---Columns-->"+getColumnsStr(daoConfig));
Log.d(TAG, "【Generate temp table】" + tempTableName);
}
} catch (SQLException e) {
Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e);
}
}
}
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();
}
private static void dropAllTables(Database db, boolean ifExists, @NonNull Class extends AbstractDao, ?>>... daoClasses) {
reflectMethod(db, "dropTable", ifExists, daoClasses);
if (DEBUG) {
Log.d(TAG, "【Drop all table】");
}
}
private static void createAllTables(Database db, boolean ifNotExists, @NonNull Class extends AbstractDao, ?>>... daoClasses) {
reflectMethod(db, "createTable", ifNotExists, daoClasses);
if (DEBUG) {
Log.d(TAG, "【Create all table】");
}
}
/**
* dao class already define the sql exec method, so just invoke it
*/
private static void reflectMethod(Database db, String methodName, boolean isExists, @NonNull 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++) {
String tempTableName = null;
try {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
if(!tablenames.contains(tableName)){
continue;
}
tempTableName = daoConfig.tablename.concat("_TEMP");
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" SELECT * FROM ").append(tempTableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
if (DEBUG) {
Log.d(TAG, "【Restore data】 to " + tableName);
}
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName);
db.execSQL(dropTableStringBuilder.toString());
if (DEBUG) {
Log.d(TAG, "【Drop temp table】" + tempTableName);
}
} catch (SQLException e) {
Log.e(TAG, "【Failed to restore data from temp table (probably new table)】" + tempTableName, e);
}
}
}
}
这个时候,再去新建一个 Product实体类,修改版本号,同时修改 onUpdate()方法;
Product代码如下:
@Entity
public class Product {
@Id
private Long Id ;
private String Name ;
public String getName() {
return this.Name;
}
public void setName(String Name) {
this.Name = Name;
}
public Long getId() {
return this.Id;
}
public void setId(Long Id) {
this.Id = Id;
}
@Generated(hash = 2099832872)
public Product(Long Id, String Name) {
this.Id = Id;
this.Name = Name;
}
@Generated(hash = 1890278724)
public Product() {
}
}
onUpdate()方法及运行结果如下:
注意:
1>:MigrationHelper.migrate()暂时只接收 SQLiteDatabase,不接收 DataBase;
2>:对加密的数据库更新是无效的;
我们在开发过程中,由于要保证数据的安全性,所以一般都是需要对 数据库加密的,那么对于 加密的数据库,该如何更新呢?我们采用的思想就是 —— 逆推,也就是说首先分析MigrationHelper.migrate()为什么不支持 对 加密数据库的更新,然后再找出对应的解决方法。
8. 分析MigrationHelper.migrate()为什么不支持对 加密数据库的 更新?
由上图可知,MigrationHelper.migrate()更新数据库时调用的是 DatabaseOpenHelper中内部类 EncrytedHelper类中的 onUpdate()方法,而该方法调用的是 DatabaseOpenHelper中的 onUpdate()方法,点击进去后发现 该onUpdate()方法没有做任何操作,如下图所示;
所以 MigrationHelper.migrate()方法 不支持 加密数据库的 更新。
9. 对加密数据库的更新 的 解决方案
9.1>:在 GreenDaoHelper 中 新建一个类 MyEncryptedSQLiteOpenHelper 继承 DaoMaster.OpenHelper,然后实现 onUpdate()、getEncryptedWritableDb(String password)方法;
9.2>:然后在 MyEncryptedSQLiteOpenHelper 内部中 再去 写一个MyEncryptedHelper类 继承 net.sqlcipher.database.SQLiteOpenHelper,目的就是代替 DatabaseOpenHelper中的 EncryptedHelper内部类
1>:首先需要添加对 sqlcipher 的依赖:
compile 'net.zetetic:android-database-sqlcipher:3.5.4@aar'
2>:然后修改 GreenDaoHelper代码如下:
/**
* Email: [email protected]
* Created by JackChen 2018/4/11 13:18
* Version 1.0
* Params:
* Description: 便于数据的读取和添加,新建GreenDaoHelper辅助类
*/
public class GreenDaoHelper extends Application {
private GreenDaoHelper Instance;
private static DaoMaster daoMaster;
private static DaoSession daoSession;
public GreenDaoHelper getInstance() {
if (Instance == null) {
Instance = this;
}
return Instance;
}
/**
* 获取DaoMaster
*
* @param context
* @return
*/
public static DaoMaster getDaoMaster(Context context) {
if (daoMaster == null) {
try{
ContextWrapper wrapper = new ContextWrapper(context) {
/**
* 获得数据库路径,如果不存在,则创建对象对象
*/
@Override
public File getDatabasePath(String name) {
// 判断是否存在sd卡
boolean sdExist = android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState());
if (!sdExist) { // 如果不存在,
Log.e("SD卡管理:", "SD卡不存在,请加载SD卡");
return null;
} else {// 如果存在
// 获取sd卡路径
String dbDir = android.os.Environment.getExternalStorageDirectory().getAbsolutePath();
dbDir += "/Android";// 数据库所在目录
String dbPath = dbDir + "/" + name;// 数据库路径
// 判断目录是否存在,不存在则创建该目录
File dirFile = new File(dbDir);
if (!dirFile.exists())
dirFile.mkdirs();
// 数据库文件是否创建成功
boolean isFileCreateSuccess = false;
// 判断文件是否存在,不存在则创建该文件
File dbFile = new File(dbPath);
if (!dbFile.exists()) {
try {
isFileCreateSuccess = dbFile.createNewFile();// 创建文件
} catch (IOException e) {
e.printStackTrace();
}
} else
isFileCreateSuccess = true;
// 返回数据库文件对象
if (isFileCreateSuccess)
return dbFile;
else
return super.getDatabasePath(name);
}
}
/**
* 重载这个方法,是用来打开SD卡上的数据库的,android 2.3及以下会调用这个方法。
*
* @param name
* @param mode
* @param factory
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
}
/**
* Android 4.0会调用此方法获取数据库。
*
* @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String,
* int,
* android.database.sqlite.SQLiteDatabase.CursorFactory,
* android.database.DatabaseErrorHandler)
* @param name
* @param mode
* @param factory
* @param errorHandler
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
}
};
/** 如果使用DevOpenHelper升级数据库时,表都会删除重建,所以需要自定义 一个类继承 DaoMaster.OpenHelper,实现onUpdate()方法即可 */
/*DaoMaster.OpenHelper helper = new DaoMaster.DevOpenHelper(wrapper,"test.db",null);
daoMaster = new DaoMaster(helper.getWritableDatabase());*/ //获取未加密的数据库
// daoMaster = new DaoMaster(helper.getEncryptedWritableDb("1234")) ; // 获取加密的数据库 下边的2种方法都是可以的
// daoMaster = new DaoMaster(helper.getEncryptedReadableDb("1234")) ;
//适用于未加密的数据库
DaoMaster.OpenHelper helper = new MySQLiteOpenHelper(wrapper,"test.db",null);
daoMaster = new DaoMaster(helper.getWritableDatabase()); //获取未加密的数据库
// 适用于加密的数据库
// MyEncryptedSQLiteOpenHelper helper = new MyEncryptedSQLiteOpenHelper(wrapper , "test.db" , null) ;
}catch (Exception e){
e.printStackTrace();
}
}
return daoMaster;
}
/**
* 获取DaoSession对象
*
* @param context
* @return
*/
public static DaoSession getDaoSession(Context context) {
if (daoSession == null) {
if (daoMaster == null) {
getDaoMaster(context);
}
daoSession = daoMaster.newSession();
}
return daoSession;
}
/**
* 适用于未加密的数据库
*/
private static class MySQLiteOpenHelper extends DaoMaster.OpenHelper {
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
private static final String UPGRADE="upgrade";
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
MigrationHelper.migrate(db,UserDao.class, PeopleDao.class, ProductDao.class);
Log.e("TAG" ,"upgrade run success"); // TAG: upgrade run success
}
}
/**
* 适用于加密的数据库
*/
private static class MyEncryptedSQLiteOpenHelper extends DaoMaster.OpenHelper{
public MyEncryptedSQLiteOpenHelper(Context context, String name) {
super(context, name);
}
public MyEncryptedSQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
super.onUpgrade(db, oldVersion, newVersion);
MigrationHelper.migrate(db , UserDao.class , PeopleDao.class , ProductDao.class);
Log.e("TAG" , "update run success") ;
}
}
}
3>:需要拷贝 EncryptedMigrationHelper类到项目中,该类与 MigrationHelper类类似,只是将 android.database.sqlite.SQLiteDatabase 替换为 net.sqlcipher.database.SQLiteDatabase,然后修改了一小部分代码,这个类的代码就不贴了;
最后,一定不要忘记添加权限: