Android: скопировать базу данных из папки ресурсов, но получить только пустой файл - PullRequest
7 голосов
/ 25 мая 2011

ребята, у меня проблема при копировании базы данных из локальной папки ресурсов в каталог / data / data / package_name / databaseПоскольку я использую учебник http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/, я могу получить только пустой файл.

Я процитировал часть метода copyDataBase (), и нет никакой разницы.Каждый раз, когда приложение запускается, оно создает каталог и пустую базу данных.Так есть ли способ заставить copyDataBase () работать?

Большое спасибо !!

Ответы [ 5 ]

15 голосов
/ 01 июля 2011

Почему бы вам не скопировать из активов? Это совершенно нормально. Но вы не можете сделать это в onCreate, в этот момент пустая база данных уже создана. Вам нужно сделать это заранее. Я обычно делаю это в переопределении getWriteableDatabase, что-то вроде

public synchronized SQLiteDatabase getWritableDatabase() {
    SQLiteDatabase db = null;

    if (!doesDatabaseExist()) {
        try {
            copyDatabase();
            db = super.getWritableDatabase();
        } catch(Exception ex) {
            Log.e("Database Log", getDatabasePath() + " failed to copy correctly. " + ex.getLocalizedMessage());
        }
    }
    else {
        db = super.getWritableDatabase();
    }

    return db;
}
1 голос
/ 21 июля 2013

Я не знаю, является ли это все еще полезным, но вот решение для других, которые добираются сюда, чтобы увидеть awnser.Код, который вы использовали, работает для большинства телефонов, некоторые старые телефоны ведут себя по-разному с помощью функции getReadableDatabase ().Поэтому ваша проблема не в функции copyDataBase, а в функции createDataBase.

в createDataBase () есть следующая проверка:

this.getReadableDatabase();

Эта проверка проверяет, существует ли уже база данных спредоставленное имя и, если нет, создает пустую базу данных, так что она может быть перезаписана с той, что в папке ресурсов.На более новых устройствах это работает безупречно, но есть некоторые устройства, на которых это не работает.В основном старые устройства.Я не знаю точно, почему, но похоже, что функция getReadableDatabase () не только получает базу данных, но и открывает ее.Если вы затем скопируете базу данных из папки ресурсов поверх нее, у нее все еще есть указатель на пустую базу данных, и вы получите таблицу несуществующих ошибок.

Таким образом, чтобы заставить его работать на всех устройствах, вы должны изменить его на следующие строки:

SQLiteDatabase db = this.getReadableDatabase();
if (db.isOpen()){
    db.close();
}

Даже если база данных открыта в чеке, она после этого закрывается, и онабольше не доставит вам хлопот.

0 голосов
/ 20 февраля 2013

Вот простой и удобный код, который я использую:

public class DataBaseImportHelper {
    private DataBaseImportHelper() {}; // Avoid instantiation

/**
 * Creates a empty database on the system and rewrites it with your own database.
 */
public static boolean importDataBase(Context context) {
    InputStream myInput = null;
    OutputStream myOutput = null;
    try {
        // Open local db from assets as the input stream
        myInput = context.getAssets().open(DATABASE_NAME);
        createEmptyDatabase(context); // See this method below
        // Open the empty db as the output stream
        myOutput = new FileOutputStream(getDatabaseFile(context));

        // 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();
        myInput.close();
        myOutput.close();
        return true;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return false;
}

/**
 * Check if the database already exists.
 * @return true if it exists, false if it doesn't
 */
public static boolean isDatabaseExists(Context context) {
    return getDatabaseFile(context).exists();
}

private static File getDatabaseFile(Context context) {
    return context.getDatabasePath(DatabaseHelper.DATABASE_NAME);
}

/**
 * Create an empty database into the default application database
 * folder.So we are gonna be able to overwrite that database with our database
 */
private static void createEmptyDatabase(Context context) {
            // use anonimous helper to create empty database
    new SQLiteOpenHelper(context, DatabaseHelper.DATABASE_NAME, null, 1) {
                    // Methods are empty. We don`t need to override them
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
        }
    }.getReadableDatabase().close();
}

}

И используя в коде:

if(!DataBaseImportHelper.isDatabaseExists(this)){
    if (!DataBaseImportHelper.importDataBase(this)){
            throw new IllegalStateException("Database doesn`t exist and hasn`t been copied!");
    }
}
0 голосов
/ 21 июля 2012

в правом примере выше работал для меня так:

db = super.getWritableDatabase();
db.close;
copyDatabase();

в противном случае я получил ошибку ввода-вывода;

0 голосов
/ 25 мая 2011

Я бы не стал копировать любую базу данных из папки assets. Если вам нужны какие-то стандартные записи в вашей базе данных, вы можете добавить их, используя INSERT s в вашем onCreate() -методе..


Обновление: Поскольку за него проголосовали за то, что он ошибался (что правильно), и я не могу его удалить, вот небольшое обновление.

Я бы сказал , это зависит от того, сколько стандартных записей вы хотите добавить в свою базу данных.Если это всего лишь один или два, доставка упакованной БД может не стоить.

В любом случае, некоторые приложения поставляются с довольно большими базами данных (например, набор рецептов).Очевидно, что вы не можете добавить все это в код.

  • Для небольших тестовых записей я все же предпочел бы просто добавить их в onCreate().
  • Для больших баз данных вам следуетпредварительно заполните их и отправьте вместе с вашим приложением.

Чтобы работать позже, вам необходимо скопировать файл базы данных из assets/ в папку приложения.Для вас есть хорошая библиотека: android-sqlite-asset-helper

...