Android SQLiteCantOpenDatabaseExeption由于未知错误

问题描述:

我正在尝试编写一个扩展SQLiteOpenHelper类的android应用程序。不幸的是,由于SQLiteCantOpenDatabaseException,我有一个android测试失败。Android SQLiteCantOpenDatabaseExeption由于未知错误

这里是一个扩展了SQLiteOpenHelper数据库辅助类:

public class ToDoDbHelper extends SQLiteOpenHelper { 

// must be incremented upon schema change 
private static final int DATABASE_VERSION = 1; 

static final String DATABASE_NAME = "todo.db"; 

private final Context mContext; 

public ToDoDbHelper(Context context) { 
    super(context, DATABASE_NAME, null, DATABASE_VERSION); 
    mContext = context; 
} 

@Override 
public void onCreate(SQLiteDatabase sqLiteDatabase) { 
    File dbFile = mContext.getDatabasePath(DATABASE_NAME); 
    // database already exists 
    if(dbFile.exists()) { 
     return; 
    } 

    // Create a table to hold our labels 
    final String SQL_CREATE_LABEL_TABLE = "CREATE TABLE" + TaskLabel.TABLE_NAME + " (" + 
      TaskLabel._ID + " INTEGER PRIMARY KEY," + 
      TaskLabel.COLUMN_LABEL + " TEXT NOT NULL " + 
      ");"; 

    // Create a table to hold our priorities 
    final String SQL_CREATE_PRIORITY_TABLE = "CREATE TABLE" + TaskPriority.TABLE_NAME + " (" + 
      TaskPriority._ID + " INTEGER PRIMARY KEY," + 
      TaskPriority.COLUMN_PRIORITY + " TEXT NOT NULL " + 
      ");"; 

    final String SQL_INSERT_PRIORITY_TABLE = "INSERT INTO " + TaskLabel.TABLE_NAME + 
      " VALUES (" + Resources.getSystem().getString(R.string.priority_none) + ")," + 
      " (" + Resources.getSystem().getString(R.string.priority_low) + ")," + 
      " (" + Resources.getSystem().getString(R.string.priority_med) + ")," + 
      " (" + Resources.getSystem().getString(R.string.priority_high) + 
      ");"; 

    // Create a table to hold our tasks 
    final String SQL_CREATE_TASK_TABLE = "CREATE TABLE " + TaskEntry.TABLE_NAME + " (" + 
      TaskEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + 
      TaskEntry.COLUMN_CREATE_DATE + " INTEGER NOT NULL," + 
      TaskEntry.COLUMN_DUE_DATE + " INTEGER," + 
      TaskEntry.COLUMN_TITLE + " TEXT NOT NULL," + 
      TaskEntry.COLUMN_DETAIL + " TEXT," + 
      TaskEntry.COLUMN_IS_COMPLETED + " INTEGER NOT NULL," + 
      TaskEntry.COLUMN_IS_DELETED + " INTEGER NOT NULL," + 
      TaskEntry.COLUMN_REMINDER_ADDED + " INTEGER NOT NULL," + 
      TaskEntry.COLUMN_LABEL_ID + " INTEGER NOT NULL," + 
      TaskEntry.COLUMN_PRIORITY_ID + " INTEGER NOT NULL," + 
      TaskEntry.COLUMN_PARENT_TASK_ID + " INTEGER," + 

      // Set up the priority column as a foreign key to the priority table 
      " FOREIGN KEY (" + TaskEntry.COLUMN_PRIORITY_ID + ") REFERENCES " + 
      TaskPriority.TABLE_NAME + "(" + TaskPriority._ID + "), " + 

      // Set up label column as a foreign key to the label table 
      " FOREIGN KEY (" + TaskEntry.COLUMN_LABEL_ID + ") REFERENCES " + 
      TaskLabel.TABLE_NAME + "(" + TaskLabel._ID + "));"; 

    sqLiteDatabase.execSQL(SQL_CREATE_LABEL_TABLE); 
    sqLiteDatabase.execSQL(SQL_CREATE_PRIORITY_TABLE); 
    sqLiteDatabase.execSQL(SQL_INSERT_PRIORITY_TABLE); 
    sqLiteDatabase.execSQL(SQL_CREATE_TASK_TABLE); 
} 

// this function to be implemented if DATABASE_VERSION is incremented (i.e. if schema changes) 
@Override 
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { 
} 
} 

下面是调用类的测试:

@Test 
public void testCreateDb() throws Throwable { 

    mContext.deleteDatabase(ToDoDbHelper.DATABASE_NAME); 

    SQLiteDatabase db = new ToDoDbHelper(
      mContext).getWritableDatabase(); 

    // make sure the database is open 
    assertEquals(true, db.isOpen()); 

在这条线发生异常:

 SQLiteDatabase db = new ToDoDbHelper(
      mContext).getWritableDatabase(); 

这里是堆栈跟踪:

android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error 
(code 14): Could not open database 
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method) 
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:207) 
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:191) 
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463) 
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185) 
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177) 
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:806) 
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:791) 
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694) 
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:571) 
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223) 
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163) 
at com.todo.group1.todo.data.TestDb.testCreateDb(TestDb.java:47) 
at java.lang.reflect.Method.invoke(Native Method) 
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
at org.junit.runners.Suite.runChild(Suite.java:128) 
at org.junit.runners.Suite.runChild(Suite.java:27) 
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
at org.junit.runner.JUnitCore.run(JUnitCore.java:115) 
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:59) 
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:262) 
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1879) 

我曾尝试:

  1. 清除应用数据
  2. 卸载
  3. 模拟器上进行的,而不是我的设备
  4. 重命名数据库文件
  5. 添加READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限运行测试到Android Manifest。

但无论我做什么,抛出异常并且永远不会创建数据库(onCreate()永远不会被调用)。我该怎么办?任何帮助表示赞赏。

+0

如果您使用的是Android 6+(M),那么您可能应该尝试在运行时请求权限。 –

+0

您确定要使用Junit来做到这一点吗?通常你只是模拟一个数据库。 –

+0

@DmytroKarataiev就是这样。我在运行时请求中使用了android开发人员文档来修复它。谢谢! – jwb1092

决定把我的评论作为一个答案在这里,因为它解决了这个问题,甚至能够帮助别人的未来:

在Android 6+(M)上,您应该在运行时请求权限以访问数据库。 Android开发者指南:https://developer.android.com/training/permissions/requesting.html

我发现你在两次SQL创建查询中缺少白色空白。

例:

final String SQL_CREATE_LABEL_TABLE = "CREATE TABLE" // you missing a blank after TABLE 

请再次仔细检查所有的语句:)

+0

虽然这只会在CRUD操作中出现问题。它不应该阻止数据库文件被打开 –

+0

谢谢,这是测试在启动时显示的问题之一。 – jwb1092