Собственная база данных на Android с возможностью обновления

Скорее всего вы уже находили множество примеров создания собственной базы данных, которые являются копированием друг-друга и преимущественное большинство которых просто не обновляются. Потому я решил выложить пример использование заранее созданной БД, с простой реализацией обновления данных.

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

Почему не работает обычный способ.

В примерах которые можно найти в интернете в большем обилии, при обращении к вашей БД, приходится вызывать её с помощью метода createDatabase(), которая копирует вашу заранее созданную базу в папку приложения. Но при вызове данного метода Android не обращается к методу onUpdate() , потому даже если вы измените версию базы, ничего не произойдёт, так как не произойдёт сравнение её версий. 
Метод onUpdate() вызывается только в случае обращения к базе данных с помощью методов getWritableDatabase() или getReadableDatabase(), в этом случае база создается и копируется если не существовала ранее и вызывается метод onUpdate(),если база уже существовала. Но если вы попробуете в методе onUpdate() удалить прошлую версию БД — приложение закроется с крешем, так как метод обновления будет вызван (а значит и база будет удалена) раньше чем будет создана новая, а потому получить доступ к несуществующей в этот момент базе не удастся.

Как обновить собственную базу данных.

Для того, чтобы удалить старую и обновить БД  придется вручную контролировать её версию и сделать это до вызова метода onUpdate(), чтобы избежать попытки её открытия до её фактического создания. Для этого будем использовать собственный метод обновления, а версии хранить и контролировать с помощью SharedPreferences.
Для использования собственной базы данных в Android создайте новый класс ExternalDbOpenHelper и поместите в него приведённый ниже код.



import android.content.Context;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.preference.PreferenceManager;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
* Created by AwesomeDevelop on 24.12.2014.
*/
public class ExternalDbOpenHelper extends SQLiteOpenHelper
{
private static final String DATABASE_NAME = "db.sqlite3"; // Название файла с БД
private static final int DATABASE_VERSION = 1; //Версия БД
private static final String SP_KEY_DB_VER = "db_ver";
private final Context mContext;

public ExternalDbOpenHelper(Context context, String DB_NAME) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = context;
initialize();
}

/**
* Инициализация БД. Создание новой если ранее не существовала.
*/
private void initialize() {
if (databaseExists()) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(mContext);
int dbVersion = prefs.getInt(SP_KEY_DB_VER, 1);
if (DATABASE_VERSION != dbVersion) {
File dbFile = mContext.getDatabasePath(DATABASE_NAME);
if (!dbFile.delete()) {
// Log.w(TAG, "Невозможно обновить БД");
}
}
}
if (!databaseExists()) {
createDatabase();
}
}

/**
* Проверка существования файла БД. Если существует - возвращает true.
* @return
*/
private boolean databaseExists() {
File dbFile = mContext.getDatabasePath(DATABASE_NAME);
return dbFile.exists();
}

/**
* Создание БД, копирование файла из Assets.
*/
private void createDatabase() {
String parentPath = mContext.getDatabasePath(DATABASE_NAME).getParent();
String path = mContext.getDatabasePath(DATABASE_NAME).getPath();

File file = new File(parentPath);
if (!file.exists()) {
if (!file.mkdir()) {
// Log.w(TAG, "Невозможно создать папку БД");
return;
}
}

InputStream is = null;
OutputStream os = null;
try {
is = mContext.getAssets().open(DATABASE_NAME);
os = new FileOutputStream(path);

byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
os.flush();
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = prefs.edit();
editor .putInt(SP_KEY_DB_VER, DATABASE_VERSION);
editor.commit();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

@Override
public void onCreate(SQLiteDatabase db) {
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion) {
}
}


Для работы данного класса, вам необходимо только указать название файла с созданной вами базой данных и её версию. Как только версия БД будет увеличена — старая её версия будет удалена, а новый файл БД скопирован. Но не пробуйте понизить версию, как и при обычном использовании будет получена ошибка о невозможности выполнить DownGrade и приложение будет закрыто. 
Работа с БД осуществляется стандартными для Android способами, потому вы можете работать с ней, как с стандартной Sqlite базой.
Открытие БД.

ExternalDbOpenHelper dbOpenHelper = new ExternalDbOpenHelper(this, DB_NAME);

SQLiteDatabase database= dbOpenHelper.getWritableDatabase();

Получить данные можно, к примеру, вот так:

data = new ArrayList();

Cursor dataCursor = database.query(
TABLE_NAME,
new String[] { DATA_NAME,DATA_IMAGE},
null, null, null, null,
DATA_NAME);
dataCursor.moveToFirst();


if(!dataCursor.isAfterLast()){
do {
String image =dataCursor.getString(1);
String name = dataCursor.getString(0);
data.add(new BrandData(name,image));

} while (dataCursor.moveToNext());
}
dataCursor.close();

И так, для использование заранее созданной базы данных необходимо:
  1. Создать файл базы данных Sqlite с любым наполнением, о том как это сделать можно прочитать тут, а для создания использовать Navicat .
  2. Поместить созданный файл в папку Assets.
  3. Создать класс ExternalDbOpenHelper и поместить в него код, приведённый в статье.
  4. Использовать вашу БД стандартными способами, описанными в официальной документации

Автор: Taras Neduiev