恢复应用程序后打开数据库时出现net.sqlcipher.database.SQLiteException

时间:2013-09-10 03:17:55

标签: android sqlite sqlcipher

我在Android应用中使用加密的SQLCipher数据库时出现以下错误,但只是关闭和启用:

net.sqlcipher.database.SQLiteException: not an error
    at net.sqlcipher.database.SQLiteDatabase.dbopen(Native Method)
    at net.sqlcipher.database.SQLiteDatabase.<init>(SQLiteDatabase.java:1950)
    at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:900)
    at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:947)
    at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:195)
    at com.android.storage.DatabaseHelper.getReadable(DatabaseHelper.java:99)
    ...

我在assets/libs/文件夹中有正确的文件,因为数据库大部分时间都能正常运行。但是,每隔一段时间我就会看到这个错误。我现在已经在手机上看到了这两次,并且在经过数小时不活动后恢复应用程序之后一直都是这样(如果从内存中清除了用户在db中的oauth令牌)。

我只从Application :: onCreate()方法调用“SQLiteDatabase.loadLibs(this)”,所以我的预感是这不是在简历上调用而是抛出错误。 这听起来有可能吗?如果是这样,我应该在哪里调用loadLibs?用户可以在任何活动中输入应用程序,如果令牌不在内存中,我将访问数据库。我看到我的选项是在每个Activity :: onCreate上调用loadLibs,或者每当我尝试打开db时调用它。 如果我这样多次调用它会导致任何伤害或性能问题吗?

1 个答案:

答案 0 :(得分:1)

您可以考虑将SQLiteDatabase.loadLibs(this);移动到net.sqlcipher.database.SQLiteOpenHelper的应用程序子类。然后,您可以将Application子类的静态实例作为其参数传递。类似下面的内容可能就是一个例子:

public class SchemaManager extends net.sqlcipher.database.SQLiteOpenHelper {

  private static SchemaManager instance;

  public static synchronized SchemaManager getInstance() {
    if(instance == null) {
      SQLiteDatabase.loadLibs(YourApplication.getInstance());
      instance = new SchemaManager(…)
    }
    return instance;
  }
}

对于提供的异常,Java例程调用调用sqlite3_open_v2的JNI层,设置软堆限制并设置忙超时。我建议在本地添加日志记录,以验证在发生崩溃时尝试获取SQLiteDatabase实例时是否传递了有效路径和非空密码。多次调用SQLiteDatabase.loadLibs(this);不会导致明显的性能影响,一旦加载了动态库,后续调用的大部分内容都是调用System.loadLibrary(…)的映射到Runtime.getRuntime().loadLibrary(…)的调用。忽略。