Sqlite DB не работает на Android пирог: таких таблиц не найдено - PullRequest
2 голосов
/ 25 июня 2019
public class DBManager {


public static final String DATABASE_TABLE= "registration";

public static final String DATABASE_NAME = "userinfo.sqlite";
static final int DATABASE_VERSION = 1;
final Context context;
SQLiteDatabase db;
DatabaseHelper DBHelper;


public DBManager(Context ctx) {
    this.context = ctx;
    DBHelper = new DatabaseHelper(context);
}

private class DatabaseHelper extends SQLiteOpenHelper {

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        context.openOrCreateDatabase(DATABASE_NAME, context.MODE_PRIVATE, null);

    }

    @Override
    public void onCreate(SQLiteDatabase db) {


    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if(newVersion>oldVersion)
            try {
                copyDataBase();
            } catch (IOException e) {
                e.printStackTrace();
            }

    }

}

// ---opens the database---
public DBManager open() throws SQLException {
    db = DBHelper.getWritableDatabase();
    return this;
}

// ---closes the database---
public void close() {
    DBHelper.close();
}



//Copies database from internal memory to the activity/fragement, To use the internal db
public void createDataBase() throws IOException {

    boolean mDataBaseExist = checkDataBase();

    if (mDataBaseExist) {
        // do nothing - database already exist

    } else {

        DBHelper.getReadableDatabase();

        try {
            copyDataBase();
        } catch (IOException e) {
            throw new Error("Error copying database");
        }
    }
}

/** This method checks whether database  exists or not **/
private boolean checkDataBase() {
    SQLiteDatabase checkDB = null;

    try {
        String myPath = context.getDatabasePath(DATABASE_NAME).getPath()
                .toString();

        checkDB = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READONLY);
    } catch (SQLiteException e) {
        // database does't exist yet.
    }

    if (checkDB != null) {
        checkDB.close();
    }

    return checkDB != null ? true : false;
}


//  Creates and copies database from assets folder to internal memory,
//  must be run at least once when app is installed

public long copyDataBase() throws IOException {
    String DB_PATH = context.getDatabasePath(DATABASE_NAME).getPath()
            .toString();

    // Open your local db as the input stream
    InputStream myInput = context.getAssets().open(DATABASE_NAME);

    // Path to the just created empty db
    String outFileName = DB_PATH;

    // Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    // transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }

    // Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();
    return length;
}

Ошибка:

android.database.sqlite.SQLiteException: no such table: registration (code 1 SQLITE_ERROR): , while compiling: select * from registration where username = ? and password = ?

Ответы [ 3 ]

1 голос
/ 26 июня 2019

Ваша проблема связана с тем, что DBHelper.getReadableDatabase(); используется перед копированием.

Это используется (неправильное использование будет более подходящим) для создания базы данных папки / директойра в данных/ data / the_package / folder / directory.

  • неправильно использовать, поскольку создавать каталог просто излишне.

В результате происходит открытие базы данных, а в случаеAndroid 9+ приводит к двум дополнительным файлам, файлы -wal и -shm, создаваемые как Android 9+, по умолчанию используют ведение журнала записи.

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

Существует несколько способов обойти это.

  • База данных может быть открыта путем принудительного использования режима журнала, например, путем перезаписи метода onConfigure для вызова enableWriteAheadLogging (false) .

  • Удалите -wal и -shm перед копией файлов.

    • НЕ РЕКОМЕНДУЕТСЯ, поскольку накладные расходы на ненужное открытие и удаление созданных файлов все еще присутствуют.
  • Создайте папку database вместо вызова getReadableDatabase()

    • , хотя это рекомендуется как таковое.При использовании checkDB = SQLiteDatabase.openDatabase(myPath, null,SQLiteDatabase.OPEN_READONLY); все еще существуют ненужные накладные расходы, чтобы проверить, существует ли файл базы данных.
  • Проверьте наличие базы данных как File и, еслиего не существует, используйте метод File mkdirs для создания каталога баз данных (из любых каталогов, которые потребуются при изменении этого каталога).

    • Это рекомендуемый способ.

Этот ответ предоставляет код (см. checkDataBase метод), который выполняет последний, отмечая, что вы должны дополнительно удалить строкуDBHelper.getReadableDatabase();.

1 голос
/ 25 июня 2019

Да, в Android 9 есть два дополнительных файла, которые являются частью базы данных SQLite, и если вы скопируете базу данных поверх существующей базы данных и не удалите эти два других файла в первую очередь, то база данных будет считаться поврежденной. , См. Этот ответ: Приложение для Android с предварительно заполненной базой данных

0 голосов
/ 27 июля 2019

Я также столкнулся с подобной проблемой и решил это, добавив это в мой SQLiteOpenHelper

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

Надеюсь, что это решит вашу проблему

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...