У меня есть база данных, сохраненных в моей папке 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 или что-то изменилось?
Была аналогичная проблема, и решить это, добавив в мой SQLiteOpenHelper
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
db.disableWriteAheadLogging();
}
Видимо Андроид P установка журнала ПРАГМА-другому. Еще не знаю, если будут побочные эффекты, но, кажется, работает!
Мои проблемы с Android П была решена путем добавления 'это.закрыть()' после этого.getReadableDatabase() в метода createdatabase() метод, как показано ниже.
private void createDataBase() throws IOException {
this.getReadableDatabase();
this.close();
try {
copyDataBase();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Этот вопрос, кажется, привести к аварии гораздо чаще на 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) {
}
}
Я столкнулся с подобной проблеме. Я был копирование базы данных, но не от актива. Я обнаружил, что проблема не имела ничего общего с моей базы скопировав файл код на всех. Не нужно делать с файлами, которые оставили открытыми, а не закрытыми, промывки и синхронизации. Мой код, как правило, переписывает существующую базу данных неоткрытое. Что представляется новый/выбора с пирогом Android и отличается от предыдущей версии Android, в том, что когда пирог на Андроид создает базу данных SQLite, он устанавливает journal_mode в Wal (записи в журнал), по умолчанию. Я'ве никогда не использовал режим Wal и SQLite и доктора сказали, что journal_mode следует удалить по умолчанию. Проблема в том, если я перезаписать существующий файл базы данных, пусть'ы сказать, что это мой.дБ, упреждающее протоколирование, мой.дБ-Шал, по-прежнему существует и эффективно, что "перекрывает" что's в Ново скопировал мой.файл db. Когда я открыл свою базу данных, в таблице sqlite_master, как правило, содержит лишь строку для android_metadata. Все таблицы я ожидал пропали. Мое решение-это просто набор journal_mode вернуться к удалить после открытия базы данных, особенно при создании новой базы данных с пирогом Андроид.
Директива Pragma journal_mode=удалить;
Возможно, Уол лучше и там's наверное какой-то способ, чтобы закрыть базу данных, так что упреждающее протоколирование не'т получить в пути, но я не't действительно нужно, а не'т это нужно для всех предыдущих версий Android.
К сожалению, принято отвечать только на "работает" в очень конкретных случаях, но это вовсе'т дать стабильно работающие советы, чтобы избежать такой ошибки в Android 9.
Вот это:
После вызова метода close(), не только все подключения к базе данных закрыт, но дополнительные файлы журнала базы данных будут перенесены на основной .файл SQLite и удалил. Так что у вас есть одна база данных.только при использовании SQLite файл, готовый быть переписана или скопирована.
Этот ответ помог мне понять это: https://stackoverflow.com/a/35648781/297710
Я имел эту проблему в Android 9 в моей информации https://github.com/andstatus/andstatus приложение, которое имеет довольно большой набор автоматизированных тестов, которые последовательно воспроизводятся на "SQLiteException: нет такой таблицы" в нашем 9 эмулятор до этого коммита: https://github.com/andstatus/andstatus/commit/1e3ca0eee8c9fbb8f6326b72dc4c393143a70538 так что, если вы'вновь действительно интересно, вы можете запустить все тесты до и после этого совершить, чтобы увидеть разницу.
Решение без отключения Шал
Андроид 9 вводит специальный режим журнала под названием совместимость Шал (упреждающее Логгин), что позволяет базу данных "и journal_mode=Wal не на" Сохраняя поведение, сохраняя максимум одно подключение на базу данных.
Подробно здесь: https://source.android.com/devices/tech/perf/compatibility-wal
Режим SQLite в Шал подробно объясняется здесь: https://www.sqlite.org/wal.html
В качестве официальных документов в режиме Wal добавляет второй файл базы данных называется имя и "-Уол-то". Так что если ваша база данных по кличке "данных.БД" это называется "и данные-Шал.БД" в тот же каталог.
Решение сейчас, чтобы спасти и восстановить и файлы (данные.и данные-Шал дБ.дБ) на Андроид 9.
После этого он работает как в предыдущих версиях.
Аналогичная проблема, только Android устройства П влияет. Все предыдущие версии без проблем.
Отключено автоматическое восстановление на Андроид 9 устройства.
Мы сделали это, чтобы устранить. Не рекомендую для случаев производства.
Автоматическое восстановление создает копию файла базы данных в каталоге данных до функция копирования баз данных называется вспомогательной базе. Таким образом, файл.существует() возвратил значение true.
Базы данных, резервное копирование с устройства разработке отсутствует в таблице. Поэтому "не нашли стол", было по сути правильно.
Во-первых, спасибо за размещение этого вопроса. Я имел то же самое произошло. Все работает хорошо, но потом при тестировании против 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 стол и все было хорошо. Надеюсь, что кто-то еще находит это полезным. Он взял навсегда, чтобы выяснить, что конкретные запросы по-прежнему работало нормально.
Я имел то же самое у меня было приложение в версии 4 для Android, и при обновлении мой мобильный телефон, который имеет Android 9, потом я 2 дня пытался найти ошибку, спасибо за коммент в моем случае я просто должен был добавить это.закрыть ();
private void createDataBase () throws IOException {
this.getReadableDatabase ();
this.close ();
try {
copyDataBase ();
} catch (IOException e) {
throw new RuntimeException (e);
}
}
готов работает для всех версий !!
Простой ответ использовать следующую строку для путь к файлу базы данных в Pie Android и выше:
DB_NAME="xyz.db";
DB_Path = "/data/data/" + BuildConfig.APPLICATION_ID + "/databases/"+DB_NAME;
Здесь's является идеальным решением для этой проблемы:
Просто переопределить этот метод в своем `SQLiteOpenHelper класса:
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
db.disableWriteAheadLogging();
}
}
Я не могу прокомментировать принятый ответ, так что я должен открыть новый ответ.
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");
}
В версии П, основным изменением является Шал (записи журнала). Необходимо выполнить следующие два шага.
<боол имя="и db_compatibility_wal_supported" и>ложные</типа bool и GT;
частный недействительными метода createdatabase() бросает IOException {
если (андроид.ОС.Построить.Версия.SDK_INT < андроид.ОС.Построить.VERSION_CODES.П) { это.getWritableDatabase(); попробовать { copyDataBase(); } поймать (исключение IOException е) { бросить новый к RuntimeException(е); } } }
Кажется, что вы Дон'т закрыть выходной поток. Хотя это наверное не объяснить, почему БД не создается (если андроид 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();
}