Android P - 从资产复制数据库后'SQLite:没有这样的表错误'

Mic*_*l J 44 sqlite android android-9.0-pie

我有一个数据库保存在我的应用程序资产文件夹中,并在应用程序首次打开时使用以下代码复制数据库.

inputStream = mContext.getAssets().open(Utils.getDatabaseName());

        if(inputStream != null) {

            int mFileLength = inputStream.available();

            String filePath = mContext.getDatabasePath(Utils.getDatabaseName()).getAbsolutePath();

            // Save the downloaded file
            output = new FileOutputStream(filePath);

            byte data[] = new byte[1024];
            long total = 0;
            int count;
            while ((count = inputStream.read(data)) != -1) {
                total += count;
                if(mFileLength != -1) {
                    // Publish the progress
                    publishProgress((int) (total * 100 / mFileLength));
                }
                output.write(data, 0, count);
            }
            return true;
        }
Run Code Online (Sandbox Code Playgroud)

上面的代码运行没有问题,但是当你尝试查询数据库时,你会得到一个SQLite:没有这样的表异常.

此问题仅发生在Android P中,所有早期版本的Android都能正常工作.

这是Android P的已知问题还是有些变化?

Ram*_*les 51

有一个类似的问题,并解决了这个添加到我的SQLiteOpenHelper

    @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);
        db.disableWriteAheadLogging();
    }
Run Code Online (Sandbox Code Playgroud)

显然Android P将PRAGMA Log设置为不同.仍然不知道是否会产生副作用,但似乎有效!

  • 很好的答案,但对于挑剔,"onConfigure"是一个更好的地方.`onConfigure`的javadoc特别提到它是`enableWriteAheadLogging`这样的地方.在我的测试中,两个地方都在努力解决Android 9上的问题. (3认同)
  • 工作由我来做!如果在我的情况下仅在 9 Android 版本上出现“问题”: if(Build.VERSION.SDK_INT >= 28) {database.disableWriteAheadLogging();} (2认同)

小智 32

通过在createDataBase()方法中的this.getReadableDatabase()之后添加'this.close()',我解决了Android P的问题,如下所示.

private void createDataBase() throws IOException {
    this.getReadableDatabase();
    this.close(); 
    try {           
        copyDataBase();            
    } catch (IOException e) {           
        throw new RuntimeException(e);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我遇到了确切的问题,解决方案也起作用,但是我对该问题感到好奇,为什么以及如何解决Android P中的问题? (3认同)

rmt*_*eis 25

这个问题似乎导致Android P上的崩溃比以前的版本更频繁,但它不是Android P本身的错误.

问题是,您为其分配值的行将String filePath打开与从资产复制文件时保持打开的数据库的连接.

要解决此问题,请替换该行

String filePath = mContext.getDatabasePath(Utils.getDatabaseName()).getAbsolutePath();
Run Code Online (Sandbox Code Playgroud)

使用代码获取文件路径值,然后关闭数据库:

MySQLiteOpenHelper helper = new MySQLiteOpenHelper();
SQLiteDatabase database = helper.getReadableDatabase();
String filePath = database.getPath();
database.close();
Run Code Online (Sandbox Code Playgroud)

并且还添加了一个内部帮助器类:

class MySQLiteOpenHelper extends SQLiteOpenHelper {

    MySQLiteOpenHelper(Context context, String databaseName) {
        super(context, databaseName, null, 2);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 道歉,你是对的.我忽略了我之前调用过这个(相当无意义的)代码:`openOrCreateDatabase(Utils.getDatabaseName(),MODE_PRIVATE,null);`这保持了与数据库的开放连接并导致了问题.我已经删除了该代码,一切正常.谢谢您的帮助! (3认同)

KGB*_*ird 6

我遇到了类似的问题.我正在复制数据库,但不是来自资产.我发现问题与我的数据库文件复制代码完全没有关系.它也与处于打开,未关闭,刷新或同步的文件有关.我的代码通常会覆盖现有的未打开的数据库.Android Pie与Android的先前版本不同之处在于,当Android Pie创建SQLite数据库时,它默认将journal_mode设置为WAL(预写日志记录).我从未使用过WAL模式,SQLite文档说默认情况下journal_mode应该是DELETE.问题是如果我覆盖现有的数据库文件,我们称之为my.db,预写日志my.db-wal仍然存在,并且有效地"覆盖"新复制的my.db文件中的内容.当我打开我的数据库时,sqlite_master表通常只包含一行android_metadata.我所期待的所有表都丢失了.我的解决方案是在打开数据库后简单地将journal_mode设置回DELETE,尤其是在使用Android Pie创建新数据库时.

PRAGMA journal_mode = DELETE;

也许WAL更好,并且可能有一些方法可以关闭数据库,以便预写日志不会妨碍但是我并不真正需要WAL并且不需要它用于所有以前版本的Android.