Суть проблемы

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

Как создать рабочую базу SQLite

Чтобы создать базу заранее на ПК, можно воспользоваться SQLite Database Browser, доступным для большинства платформ. Допустим, вы уже создали простую базу данных в файле yourdb.sqlite3 c одной таблицей friends, которая содержит список ваших друзей с двумя полями — id и name. Чтобы эта база корректно работала на Android-устройстве, нужно выполнить 2 модификации.

  • Переименовать поле первичного ключа из id в _id. Это можно легко сделать, нажав на кнопку «Modify Table», выбрав нужную таблицу и нужное поле.
  • Добавить таблицу с метаданными android_metadata. Для этого переходим на вкладку «Execute SQL» и вставляем туда нехитрый код:
CREATE TABLE android_metadata (locale TEXT);

INSERT INTO android_metadata VALUES ('en_US');

Жмем кнопку «Execute query» и радуемся, потому что база готова. После этих манипуляций база примет вид:



Осталось скопировать базу в папку asset вашего проекта.

Как скопировать и открыть базу на устройстве. Реализация класса ExternalDbOpenHelper

Итак, база готова и лежит в папке assets. Теперь опишем класс ExternalDbOpenHelper, унаследованный от SQLiteOpenHelper. Для нас важен факт, что на девайсе базы приложения хранятся в папке dada/dada/<имя вашего пакета>/databases/ — именно туда мы будем копировать нашу готовую базу. Листинг с комментариями представлен ниже:

package by.idev.android.ownsqlitedb.dbhelper;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class ExternalDbOpenHelper extends SQLiteOpenHelper {
//Путь к папке с базами на устройстве
public static String DB_PATH;
//Имя файла с базой
public static String DB_NAME;
public SQLiteDatabase database;
public final Context context;
public SQLiteDatabase getDb() {
return database;
}
public ExternalDbOpenHelper(Context context, String databaseName) {
super(context, databaseName, null, 1);
this.context = context;
//Составим полный путь к базам для вашего приложения
String packageName = context.getPackageName();
DB_PATH = String.format("//data//data//%s//databases//", packageName);
DB_NAME = databaseName;
openDataBase();
}
//Создаст базу, если она не создана
public void createDataBase() {
boolean dbExist = checkDataBase();
if (!dbExist) {
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
Log.e(this.getClass().toString(), "Copying error");
throw new Error("Error copying database!");
}
} else {
Log.i(this.getClass().toString(), "Database already exists");
}
}
//Проверка существования базы данных
private boolean checkDataBase() {
SQLiteDatabase checkDb = null;
try {
String path = DB_PATH + DB_NAME;
checkDb = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READONLY);
} catch (SQLException e) {
Log.e(this.getClass().toString(), "Error while checking db");
}
//Андроид не любит утечки ресурсов, все должно закрываться
if (checkDb != null) {
checkDb.close();
}
return checkDb != null;
}
//Метод копирования базы
private void copyDataBase() throws IOException {
// Открываем поток для чтения из уже созданной нами БД
//источник в assets
InputStream externalDbStream = context.getAssets().open(DB_NAME);
// Путь к уже созданной пустой базе в андроиде
String outFileName = DB_PATH + DB_NAME;
// Теперь создадим поток для записи в эту БД побайтно
OutputStream localDbStream = new FileOutputStream(outFileName);
// Собственно, копирование
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = externalDbStream.read(buffer)) > 0) {
localDbStream.write(buffer, 0, bytesRead);
}
// Мы будем хорошими мальчиками (девочками) и закроем потоки
localDbStream.close();
externalDbStream.close();
}
public SQLiteDatabase openDataBase() throws SQLException {
String path = DB_PATH + DB_NAME;
if (database == null) {
createDataBase();
database = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READWRITE);
}
return database;
}
@Override
public synchronized void close() {
if (database != null) {
database.close();
}
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}

Теперь этот класс можно использовать в любом приложении. Все, что нам нужно — это передать в конструктор имя файла БД и контекст (чаще всего Application).

Пример использования

Создадим для примера приложение с простой архитектурой и минимальной функциональностью: при его запуске оно будет выводить в виде списка имена друзей из базы данных.

Внимание! Перед каждым тестовым запуском приложения удаляйте его с устройства. Файл с базой данных создается только при первом запуске, что может быть неудобно и вызвать «непонятки». Я предупреждал! =)

Проект содержит всего одну активность, унаследованную от ListActivity, со следующей разметкой:

<!--?xml version="1.0" encoding="utf-8"?-->

android:orientation=»vertical»

android:layout_width=»fill_parent»

android:layout_height=»fill_parent»

>

android:layout_width=»fill_parent»

android:layout_height=»wrap_content»

android:text=»@string/hello»

/> android:id=»@android:id/list»

android:layout_width=»fill_parent»

android:layout_height=»fill_parent»>

И следующей логикой:

package by.idev.android.ownsqlitedb.activity;

import java.util.ArrayList;
import by.idev.android.ownsqlitedb.R;
import by.idev.android.ownsqlitedb.R.layout;
import by.idev.android.ownsqlitedb.dbhelper.ExternalDbOpenHelper;
import android.app.Activity;
import android.app.ListActivity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class IdevOwnSqliteDbActivity extends ListActivity {
private static final String DB_NAME = "yourdb.sqlite3";
//Хорошей практикой является задание имен полей БД константами
private static final String TABLE_NAME = "friends";
private static final String FRIEND_ID = "_id";
private static final String FRIEND_NAME = "name";
private SQLiteDatabase database;
private ListView listView;
private ArrayList friends;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Наш ключевой хелпер
ExternalDbOpenHelper dbOpenHelper = new ExternalDbOpenHelper(this, DB_NAME);
database = dbOpenHelper.openDataBase();
//Все, база открыта!
fillFreinds();
setUpList();
}
private void setUpList() {
//Используем стандартный адаптер и layout элемента для краткости
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, friends));
listView = getListView();
//Подарим себе тост — для души
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View view,
int position,long id) {
Toast.makeText(getApplicationContext(),
((TextView) view).getText() +
" could be iDev's friend",
Toast.LENGTH_SHORT).show();
}
});
}
//Извлечение элементов из базы данных
private void fillFreinds() {
friends = new ArrayList<String>();
Cursor friendCursor = database.query(TABLE_NAME,
new String[] {FRIEND_ID, FRIEND_NAME},
null, null,null,null,
FRIEND_NAME);
friendCursor.moveToFirst();
if(!friendCursor.isAfterLast()) {
do {
String name = friendCursor.getString(1);
friends.add(name);
} while (friendCursor.moveToNext());
}
friendCursor.close();
}
}

Вот и все, теперь вы можете с улыбкой лицезреть на экране следующую картину (если будете использовать нашу базу):



Исходники можно скачать тут: IdevOwnSqliteDb. Вопросы, комментарии и рекомендации always welcome.

Happy coding!

При написанни статьи использовался следующий источник: http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/

Вакантное место: ведущий Android разработчик в компании Softeq Development

Что будете делать Вы?

  • разрабатывать приложения для мобильных Android устройств
  • работать с заказчиками мирового уровня

Что нужно от Вас?

  • опыт разработки под Android от одного года
  • отличное знание основ Java
  • отличное знание основ Android
  • хорошее знание С/С++ и опыт работы с NDK
  • знание принципов ООП и способность эффективно применять их в архитектуре приложения
  • знание и умение применять на практике шаблоны проектирования
  • английский язык: уметь уверенно читать и писать, разговорный приветствуется

Большим плюсом будет:

  • опыт кросс-платформенного программирования

Сайт: www.softeq.by, www.softeq.com

Cтраничка в Facebook: http://www.facebook.com/pages/Softeq/110374298801

Страничка в VK: http://vk.com/club21079655

Контактная информация:

Ждем Ваше резюме на jobs@softeq.by!

Если вы хотите узнать о вакансии и нашей компании больше, Вы можете связаться с менеджером по персоналу Ириной Протащик:

Skype: irina.protaschik

E-mail: irina.protaschik@softeq.com

Моб.: +375 29 175 47 00, +375 29 234 47 00

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *