База данных Sqlite копируется на мобильные телефоны Samsung, но происходит сбой на мобильных устройствах с ОС MIUI 10

Копирование базы данных sqlite работает на мобильных устройствах Samsung, но не работает на телефонах Redmi, Oppo или Vivo, например, в операционной системе Redmi MIUI Global 10.3.12 происходит сбой.

Я ожидаю работы на всех платформах.

Пробовал устанавливать во все модели в эмуляторах. работает нормально на всех устройствах, но проблема связана с мобильными интерфейсами Vivo, Redmi, Oppo.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    lvProduct = (ListView) findViewById(R.id.listview_product);
    mDBHelper = new DatabaseHelper(this);
    File database = getApplicationContext().getDatabasePath(DatabaseHelper.DBNAME);
    if (false == database.exists()) {
        mDBHelper.getReadableDatabase();
        //Copy db
        if (copyDatabase(this)) {
            Toast.makeText(this, "Copy database succes", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "Copy data error", Toast.LENGTH_SHORT).show();
            return;
        }
    }
}

Моя база данных не копируется в пользовательском интерфейсе Redmi, Vivo, Oppo, но отлично работает в мобильных телефонах Samsung.

введите здесь описание изображения


person Alfred kommina    schedule 12.08.2019    source источник


Ответы (1)


Ваша проблема, скорее всего, связана с mDBHelper.getReadableDatabase();

То есть в Android 9+ ведение журнала по умолчанию было изменено с журнала на WAL (запись = опережающее ведение журнала).

Что делает getReadableDatabase (или getWritableDatabase), так это открывает совершенно новую пустую базу данных и заполняет ее таблицей android_metadata. Фактические данные записываются не в файл базы данных, а в файл -wal (т. е. в файл базы данных с суффиксом -wal).

При копировании базы данных база данных, созданная с помощью getReadableDatabase, перезаписывается, но файлы -wal (а также -shm) остаются. Поэтому, когда база данных открывается, SQLite обнаруживает, что файл -wal не является правильным файлом -wal, и не может его открыть. SDK обрабатывает это, создавая новую пустую базу данных, которую можно использовать, и, следовательно, имя таблицы не найдено.

Есть ряд исправлений.

  • Вы можете переопределить метод onConfigure помощника базы данных и вызвать отключитьWriteAheadLogging

    • This is not recommended as you lose the advantages of WAL
  • Вы можете использовать метод getReadableDatabase для базы данных с другим именем.

    • I've never come across this, but in theory it would work. Again this is not recommended as it's still relatively resource hungry.
  • Вы можете удалить файлы -wal и -shm, если они существуют до или сразу после копирования.

    • This is not recommended as it's wasteful of resources (opening a database is relatively expense resource wise).
  • Вы можете заменить getReadableDatabase файлом mkdirs. То есть getReadableDatabase исторически был закодирован как хак, чтобы обойти ошибку NO ENT из-за того, что папка databases не существует при установке приложения.

  • Я рекомендую делать это не после проверки существующей базы данных, а как часть проверки с использованием чего-то, основанного на: -

    private boolean checkDataBase(Context context, String databaseName) { /** * Не открывает базу данных, вместо этого проверяет, существует ли файл * также создает каталог баз данных, если он не существует * (настоящая причина открытия базы данных, что, по-видимому, приводит к проблемам) */

    File db = new File(context.getDatabasePath(databaseName).getPath()); //Get the file name of the database
    Log.d("DBPATH","DB Path is " + db.getPath()); //TODO remove for Live App
    if (db.exists()) return true; // If it exists then return doing nothing
    
    // Get the parent (directory in which the database file would be)
    File dbdir = db.getParentFile();
    // If the directory does not exits then make the directory (and higher level directories)
    if (!dbdir.exists()) {
        db.getParentFile().mkdirs();
        dbdir.mkdirs();
    }
    return false;
    

    }

  • Приведенный выше код был взят из Предварительно заполненная база данных не работает в API 28, выдает исключение "нет такой таблицы", что немного более полно.

Исправить

Применительно к вашему коду это может быть: -

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    lvProduct = (ListView) findViewById(R.id.listview_product);
    mDBHelper = new DatabaseHelper(this);
    File database = getApplicationContext().getDatabasePath(DatabaseHelper.DBNAME);
    if (false == database.exists()) {
        File dbdir = database.getParentFile();
        if (!dbdir.exists()) {
            database.getParentFile().mkdirs();
            dbdir.mkdirs();
        }
        //Copy db
        if (copyDatabase(this)) {
            Toast.makeText(this, "Copy database succes", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "Copy data error", Toast.LENGTH_SHORT).show();
            return;
        }
    }
}
person MikeT    schedule 12.08.2019
comment
Спасибо за ответ, но все равно сбой @MikeT - person Alfred kommina; 15.08.2019