Android P - «SQLite: нет такой ошибки таблицы» после копирования базы данных из ресурсов - PullRequest
0 голосов
/ 23 мая 2018

У меня есть база данных, сохраненная в папке активов моего приложения, и я копирую базу данных, используя приведенный ниже код при первом запуске приложения.

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;
        }

Приведенный выше код запускается без проблем, но при попытке запросаБаза данных, которую вы получаете SQLite: нет таких исключений таблицы.

Эта проблема возникает только в Android P, все более ранние версии Android работают правильно.

Это известная проблема с Android P или есть что-тоизменилось?

Ответы [ 13 ]

0 голосов
/ 13 августа 2018

Во-первых, спасибо за размещение этого вопроса.У меня случилось то же самое.Все работало хорошо, но потом при тестировании на Android P Preview я получал сбои.Вот ошибка, которую я нашел для этого кода:

private void copyDatabase(File dbFile, String db_name) throws IOException{
    InputStream is = null;
    OutputStream os = null;

    SQLiteDatabase db = context.openOrCreateDatabase(db_name, Context.MODE_PRIVATE, null);
    db.close();
    try {
        is = context.getAssets().open(db_name);
        os = new FileOutputStream(dbFile);

        byte[] buffer = new byte[1024];
        while (is.read(buffer) > 0) {
            os.write(buffer);
        }
    } catch (IOException e) {
        e.printStackTrace();
        throw(e);
    } finally {
        try {
            if (os != null) os.close();
            if (is != null) is.close();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

Проблема, с которой я столкнулся, заключалась в том, что этот код прекрасно работает, НО в SDK 28+ openOrCreateDatabase больше не создает автоматически таблицу android_metadata для вас.Поэтому, если вы выполните запрос «select * from TABLE», он не найдет этот TABLE, потому что запрос начинает присматривать за «первой» таблицей, которая должна быть таблицей метаданных.Я исправил это, вручную добавив таблицу android_metadata, и все было хорошо.Надеюсь, кто-то еще найдет это полезным.Потребовалось вечно, чтобы понять, потому что определенные запросы все еще работали нормально.

0 голосов
/ 31 мая 2018

Эта проблема, по-видимому, приводит к сбою на Android P гораздо чаще, чем в предыдущих версиях, но это не ошибка на самом Android P.

Проблема в том, что ваша строка, в которой вы присваиваете значениеString filePath открывает соединение с базой данных, которое остается открытым при копировании файла из ресурсов.

Чтобы устранить проблему, замените строку

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

кодом для получения файла.Значение пути и затем закройте базу данных:

MySQLiteOpenHelper helper = new MySQLiteOpenHelper();
SQLiteDatabase database = helper.getReadableDatabase();
String filePath = database.getPath();
database.close();

А также добавьте внутренний вспомогательный класс:

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) {
    }
}
0 голосов
/ 28 мая 2018

Кажется, что вы не закрываете выходной поток.Хотя это, вероятно, не объясняет, почему БД в действительности не создается (если в Android P не добавлен буфер размером несколько МБ), рекомендуется использовать метод try-with-resource, например:

// garantees that the data are flushed and the resources freed
try (FileOutputStream 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);
    }

    // maybe a bit overkill
    output.getFD().sync();
}
...