无法在Android sqlite中创建数据库

时间:2019-02-23 22:57:25

标签: android sqlite

正在运行最新版本的Android Studio。专为API级别23及更高版本(棉花糖)构建项目,并使用Pixel XL仿真器。我已经在清单中授予了权限,并在运行时也获得了写访问权限(API 23及更高版本要求)

有一个与此相关的按钮

public void createDatabase(View view) {
    String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
    requestPermissions(permissions, 1); 
}

我在AndroidManifest.xml中也有这个

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

这是我的权限授予代码

@Override

public void onRequestPermissionsResult(int requestCode, String 
                                      permissions[], int[] grantResults) {
  switch (requestCode) {
    case 1:
        if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
            DbUtil.CreateDb(getApplicationContext().getApplicationInfo().dataDir + "/databases/game360.db");

        }
        else{
            //Permission denied.
        }
        break;
  }
}

这是DBUtil.CreateDb

public static void CreateDb(String dbPath){
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbPath, null);
    db.execSQL("CREATE TABLE if not exists user (id INTEGER PRIMARY KEY AUTOINCREMENT, " +
            "username VARCHAR NOT NULL unique, firstName VARCHAR NOT NULL, lastName VARCHAR NOT NULL)");
    ContentValues values = new ContentValues();
    values.put("username", "jj678");
    values.put("firstName", "brad");
    values.put("lastName", "pitt");
    db.insert("user",null, values);
    db.close();
}

当我在模拟器上运行应用程序并单击按钮时,我将按预期方式弹出权限弹出窗口。在我授予o权限后,create Database被调用,并且失败并显示以下堆栈跟踪(错误代码14)。知道为什么吗?

02-23 17:44:39.347 19358-19358/com.jtech.game360 E/SQLiteLog: (14) cannot open file at line 31278 of [2ef4f3a5b1]
02-23 17:44:39.347 19358-19358/com.jtech.game360 E/SQLiteLog: (14) os_unix.c:31278: (2) open(/data/user/0/com.jtech.game360/databases/game360.db) - 
02-23 17:44:39.348 19358-19358/com.jtech.game360 E/SQLiteDatabase: Failed to open database '/data/user/0/com.jtech.game360/databases/game360.db'.
    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.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:709)
        at com.jtech.game360.DbUtil.CreateDb(DbUtil.java:13)
        at com.jtech.game360.Main2Activity.onRequestPermissionsResult(Main2Activity.java:52)
        at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6553)
        at android.app.Activity.dispatchActivityResult(Activity.java:6432)

2 个答案:

答案 0 :(得分:1)

似乎您缺少databases文件夹。试试:

public static void CreateDb(String dbPath){
    File f = new File(dbPath);
    f.getParentFile().mkdirs();
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbPath, null);
    // ...
}

答案 1 :(得分:1)

由于您使用数据库的标准位置,因此不需要权限,因为它们已经存在。

此外,无需对完整路径进行硬编码,而是可以使用上下文的 getDatabasePath(),这是推荐的方法。

您遇到的问题是 dataabses 文件夹不存在,因此无法打开该文件。因此,您需要检查数据库目录/文件夹是否存在,以及是否不创建该文件夹。

此外,如果数据库存在,在获取文件时可以很容易地进行检查,以检查数据库文件夹是否存在,因此无需尝试检查目录是否存在存在,也不能 openOrCreate 数据库,也不要尝试在后续运行中添加已经存在的行。

因此 CreateDB 方法可能更有效:-

// Only context required to be passed (assuming just the one database)
public static void CreateDB(Context context) {
    File f = new File(context.getDatabasePath(DBNAME).toString()); //<<<<<<<<<< uses the recommended GetDatabasePath method
    // If DB exists no need to waste time doing anything
    if (f.exists()) {
        return;
    }
    // Creates the databases directory (or others if directories change in the future)
    if (!f.getParentFile().exists()) {
        f.getParentFile().mkdirs();
    }
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f,null); //<<<<<<<<< uses the File to create the database
    //Same code as original from now
    db.execSQL("CREATE TABLE if not exists user (id INTEGER PRIMARY KEY AUTOINCREMENT, " +
            "username VARCHAR NOT NULL unique, firstName VARCHAR NOT NULL, lastName VARCHAR NOT NULL)");
    ContentValues values = new ContentValues();
    values.put("username", "jj678");
    values.put("firstName", "brad");
    values.put("lastName", "pitt");
    db.insert("user",null, values);
    db.close();
}

工作示例

作为利用以上内容(在棒棒糖(5.0)和Pie(10.1)中进行测试)的示例(在活动中):-

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //DBUtil.CreateDb(getApplicationContext().getApplicationInfo().dataDir + "/databases/game360.db");
    DBUtil.CreateDB(this);
    SQLiteDatabase db = SQLiteDatabase.openDatabase(this.getDatabasePath(DBUtil.DBNAME).toString(),null,SQLiteDatabase.OPEN_READWRITE);
    Cursor csr = db.query("user",null,null,null,null,null,null);
    DatabaseUtils.dumpCursor(csr);
    csr.close();
    db.close();
}

运行良好,对于第一次和随后的运行,将以下输出记录到日志中:-

02-24 17:58:07.175 9579-9579/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@12c4306e
02-24 17:58:07.176 9579-9579/? I/System.out: 0 {
02-24 17:58:07.176 9579-9579/? I/System.out:    id=1
02-24 17:58:07.176 9579-9579/? I/System.out:    username=jj678
02-24 17:58:07.176 9579-9579/? I/System.out:    firstName=brad
02-24 17:58:07.176 9579-9579/? I/System.out:    lastName=pitt
02-24 17:58:07.176 9579-9579/? I/System.out: }
02-24 17:58:07.176 9579-9579/? I/System.out: <<<<<