SQLite DB在Android Pie上不起作用:找不到这样的表

时间:2019-06-25 19:09:02

标签: android sqlite

public class DBManager {


public static final String DATABASE_TABLE= "registration";

public static final String DATABASE_NAME = "userinfo.sqlite";
static final int DATABASE_VERSION = 1;
final Context context;
SQLiteDatabase db;
DatabaseHelper DBHelper;


public DBManager(Context ctx) {
    this.context = ctx;
    DBHelper = new DatabaseHelper(context);
}

private class DatabaseHelper extends SQLiteOpenHelper {

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        context.openOrCreateDatabase(DATABASE_NAME, context.MODE_PRIVATE, null);

    }

    @Override
    public void onCreate(SQLiteDatabase db) {


    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if(newVersion>oldVersion)
            try {
                copyDataBase();
            } catch (IOException e) {
                e.printStackTrace();
            }

    }

}

// ---opens the database---
public DBManager open() throws SQLException {
    db = DBHelper.getWritableDatabase();
    return this;
}

// ---closes the database---
public void close() {
    DBHelper.close();
}



//Copies database from internal memory to the activity/fragement, To use the internal db
public void createDataBase() throws IOException {

    boolean mDataBaseExist = checkDataBase();

    if (mDataBaseExist) {
        // do nothing - database already exist

    } else {

        DBHelper.getReadableDatabase();

        try {
            copyDataBase();
        } catch (IOException e) {
            throw new Error("Error copying database");
        }
    }
}

/** This method checks whether database  exists or not **/
private boolean checkDataBase() {
    SQLiteDatabase checkDB = null;

    try {
        String myPath = context.getDatabasePath(DATABASE_NAME).getPath()
                .toString();

        checkDB = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READONLY);
    } catch (SQLiteException e) {
        // database does't exist yet.
    }

    if (checkDB != null) {
        checkDB.close();
    }

    return checkDB != null ? true : false;
}


//  Creates and copies database from assets folder to internal memory,
//  must be run at least once when app is installed

public long copyDataBase() throws IOException {
    String DB_PATH = context.getDatabasePath(DATABASE_NAME).getPath()
            .toString();

    // Open your local db as the input stream
    InputStream myInput = context.getAssets().open(DATABASE_NAME);

    // Path to the just created empty db
    String outFileName = DB_PATH;

    // Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    // transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }

    // Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();
    return length;
}

错误:

android.database.sqlite.SQLiteException: no such table: registration (code 1 SQLITE_ERROR): , while compiling: select * from registration where username = ? and password = ?

3 个答案:

答案 0 :(得分:1)

是的,对于android 9,SQLite数据库中还有两个其他文件,如果您复制覆盖现有数据库的数据库,并且不先删除其他两个文件,则该数据库将认为自身已损坏。查看此答案:Ship android app with pre populated database

答案 1 :(得分:1)

您的问题是由于在复制之前使用了DBHelper.getReadableDatabase();

使用它(可能更容易使用)在data / data / the_package /文件夹/目录中创建 database 文件夹/ directoyr。

  • 滥用,因为创建目录太过夸张了。

发生的事情是,这将打开数据库,并且在Android 9+的情况下会产生两个附加文件,作为Android 9+创建的-wal和-shm文件默认使用预先写入日志记录。

将数据库文件复制到新创建的文件上时,剩下两个其他文件。复制后打开数据库时,两个文件与复制的数据库不匹配,打开失败但被捕获,导致创建了新数据库。

有几种方法可以规避。

  • 可以通过强制使用日志模式来打开数据库,例如覆盖 onConfigure 方法以调用enableWriteAheadLogging(false)

  • 在复制之前删除 -wal -shm 文件。

    • 不建议这样做,因为仍然存在不必要的打开和删除所创建文件的开销。
  • 创建数据库文件夹,而不是调用getReadableDatabase()

      尽管推荐这样做。使用checkDB = SQLiteDatabase.openDatabase(myPath, null,SQLiteDatabase.OPEN_READONLY);来查看数据库文件是否存在仍然有不必要的开销。
  • 检查数据库是否作为文件存在,如果不存在,请使用文件 mkdirs 方法创建数据库目录(如果更改此目录将需要任何目录)。

    • 推荐的方式。

This answer提供了执行后者的代码(请参见 checkDataBase 方法),并指出您还应该删除行DBHelper.getReadableDatabase();

答案 2 :(得分:0)

我也面临类似的问题,并解决了此问题,将其添加到我的SQLiteOpenHelper

@Override
public void onOpen(SQLiteDatabase db) {
    super.onOpen(db);
    db.disableWriteAheadLogging();
}

希望这可以解决您的问题