Планшет П - 'базы данных SQLite: нет такой таблицы ошибка' после копирования базы данных из активов

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

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 или что-то изменилось?

Комментарии к вопросу (9)

Была аналогичная проблема, и решить это, добавив в мой SQLiteOpenHelper

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

Видимо Андроид P установка журнала ПРАГМА-другому. Еще не знаю, если будут побочные эффекты, но, кажется, работает!

Комментарии (2)

Мои проблемы с Android П была решена путем добавления 'это.закрыть()' после этого.getReadableDatabase() в метода createdatabase() метод, как показано ниже.

private void createDataBase() throws IOException {
    this.getReadableDatabase();
    this.close(); 
    try {           
        copyDataBase();            
    } catch (IOException e) {           
        throw new RuntimeException(e);
    }
}
Комментарии (4)
Решение

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

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

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

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) {
    }
}
Комментарии (9)

Я столкнулся с подобной проблеме. Я был копирование базы данных, но не от актива. Я обнаружил, что проблема не имела ничего общего с моей базы скопировав файл код на всех. Не нужно делать с файлами, которые оставили открытыми, а не закрытыми, промывки и синхронизации. Мой код, как правило, переписывает существующую базу данных неоткрытое. Что представляется новый/выбора с пирогом Android и отличается от предыдущей версии Android, в том, что когда пирог на Андроид создает базу данных SQLite, он устанавливает journal_mode в Wal (записи в журнал), по умолчанию. Я'ве никогда не использовал режим Wal и SQLite и доктора сказали, что journal_mode следует удалить по умолчанию. Проблема в том, если я перезаписать существующий файл базы данных, пусть'ы сказать, что это мой.дБ, упреждающее протоколирование, мой.дБ-Шал, по-прежнему существует и эффективно, что "перекрывает" что's в Ново скопировал мой.файл db. Когда я открыл свою базу данных, в таблице sqlite_master, как правило, содержит лишь строку для android_metadata. Все таблицы я ожидал пропали. Мое решение-это просто набор journal_mode вернуться к удалить после открытия базы данных, особенно при создании новой базы данных с пирогом Андроид.

Директива Pragma journal_mode=удалить;

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

Комментарии (0)

К сожалению, принято отвечать только на "работает" в очень конкретных случаях, но это вовсе'т дать стабильно работающие советы, чтобы избежать такой ошибки в Android 9.

Вот это:

  1. Есть один экземпляр класса SQLiteOpenHelper в приложении для доступа к базе данных.
  2. Если нужно переписать / скопировать базу данных, закройте базу данных (и закрыть все подключения к базе данных), используя SQLiteOpenHelper.close() метод этого экземпляра и Дон'т использовать этот экземпляр SQLiteOpenHelper больше.

После вызова метода close(), не только все подключения к базе данных закрыт, но дополнительные файлы журнала базы данных будут перенесены на основной .файл SQLite и удалил. Так что у вас есть одна база данных.только при использовании SQLite файл, готовый быть переписана или скопирована.

  1. После копирования / перезаписи и т. д. создайте новый синглтон из SQLiteOpenHelper, который getWritableDatabase() метод возвращает новый экземпляр базы данных SQLite! И использовать его, пока в следующий раз вам понадобится ваша база данных для копирования / переписан...

Этот ответ помог мне понять это: https://stackoverflow.com/a/35648781/297710

Я имел эту проблему в Android 9 в моей информации https://github.com/andstatus/andstatus приложение, которое имеет довольно большой набор автоматизированных тестов, которые последовательно воспроизводятся на "SQLiteException: нет такой таблицы" в нашем 9 эмулятор до этого коммита: https://github.com/andstatus/andstatus/commit/1e3ca0eee8c9fbb8f6326b72dc4c393143a70538 так что, если вы'вновь действительно интересно, вы можете запустить все тесты до и после этого совершить, чтобы увидеть разницу.

Комментарии (0)

Решение без отключения Шал

Андроид 9 вводит специальный режим журнала под названием совместимость Шал (упреждающее Логгин), что позволяет базу данных "и journal_mode=Wal не на" Сохраняя поведение, сохраняя максимум одно подключение на базу данных.

Подробно здесь: https://source.android.com/devices/tech/perf/compatibility-wal

Режим SQLite в Шал подробно объясняется здесь: https://www.sqlite.org/wal.html

В качестве официальных документов в режиме Wal добавляет второй файл базы данных называется имя и "-Уол-то". Так что если ваша база данных по кличке "данных.БД" это называется "и данные-Шал.БД" в тот же каталог.

Решение сейчас, чтобы спасти и восстановить и файлы (данные.и данные-Шал дБ.дБ) на Андроид 9.

После этого он работает как в предыдущих версиях.

Комментарии (0)

Аналогичная проблема, только Android устройства П влияет. Все предыдущие версии без проблем.

Отключено автоматическое восстановление на Андроид 9 устройства.

Мы сделали это, чтобы устранить. Не рекомендую для случаев производства.

Автоматическое восстановление создает копию файла базы данных в каталоге данных до функция копирования баз данных называется вспомогательной базе. Таким образом, файл.существует() возвратил значение true.

Базы данных, резервное копирование с устройства разработке отсутствует в таблице. Поэтому "не нашли стол", было по сути правильно.

Комментарии (1)

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

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

    }
}

Проблема я столкнулся, был этот код работает просто отлично, но в СДК 28+ openOrCreateDatabase не автоматически создает android_metadata стол для вас. Так что если вы делаете запрос на "выбрать * из таблица" это не найти эту таблицу, поскольку запрос начинает выглядеть после "Первый" и стол, который должен быть в таблице метаданных. Я исправил это вручную, добавляя android_metadata стол и все было хорошо. Надеюсь, что кто-то еще находит это полезным. Он взял навсегда, чтобы выяснить, что конкретные запросы по-прежнему работало нормально.

Комментарии (2)

Я имел то же самое у меня было приложение в версии 4 для Android, и при обновлении мой мобильный телефон, который имеет Android 9, потом я 2 дня пытался найти ошибку, спасибо за коммент в моем случае я просто должен был добавить это.закрыть ();

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

готов работает для всех версий !!

Комментарии (0)

Простой ответ использовать следующую строку для путь к файлу базы данных в Pie Android и выше:

DB_NAME="xyz.db";
DB_Path = "/data/data/" + BuildConfig.APPLICATION_ID + "/databases/"+DB_NAME;
Комментарии (0)

Здесь's является идеальным решением для этой проблемы:

Просто переопределить этот метод в своем `SQLiteOpenHelper класса:

@Override
public void onOpen(SQLiteDatabase db) {
    super.onOpen(db);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        db.disableWriteAheadLogging();
    }
}
Комментарии (0)

Я не могу прокомментировать принятый ответ, так что я должен открыть новый ответ.

mContext.getDatabasePath() не открывает подключение к базе данных, это вовсе't даже требует существующее именем, чтобы добиться успеха (см. sources/android-28/android/app/ContextImpl.java):

@Override
public File getDatabasePath(String name) {
    File dir;
    File f;

    if (name.charAt(0) == File.separatorChar) {
        // snip
    } else {
        dir = getDatabasesDir();
        f = makeFilename(dir, name);
    }

    return f;
}

private File makeFilename(File base, String name) {
    if (name.indexOf(File.separatorChar) < 0) {
        return new File(base, name);
    }
    throw new IllegalArgumentException(
            "File " + name + " contains a path separator");
}
Комментарии (0)

В версии П, основным изменением является Шал (записи журнала). Необходимо выполнить следующие два шага.

  1. Отключить же следующей строкой в config.xml в папке значения ресурсов.

<боол имя="и db_compatibility_wal_supported" и>ложные</типа bool и GT;

  1. Внести следующие изменения в классе DBAdapter в метод метода createdatabase. Телефоны в противном случае с более ранними версиями Android аварии.

частный недействительными метода createdatabase() бросает IOException {

если (андроид.ОС.Построить.Версия.SDK_INT < андроид.ОС.Построить.VERSION_CODES.П) { это.getWritableDatabase(); попробовать { copyDataBase(); } поймать (исключение IOException е) { бросить новый к RuntimeException(е); } } }

Комментарии (0)

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

// 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();
}
Комментарии (1)