Zanim utworzymy archiwum .zip z bazą danych należy lekko zmodyfikować już istniejącą bazę. Plik z bazą należy otworzyć za pomocą odpowiedniego narzędzia, które pozwoli na dodanie tabeli oraz zmianę nazwy kluczy głównych. Jednym z takich narzędzi jest wtyczka dla przeglądarki internetowej Firefox o nazwie: SQLite Manager. Do istniejącej bazy należy wprowadzić nową tabelę za pomocą polecenia SQL:
CREATE TABLE "android_metadata" ("locale" TEXT DEFAULT 'en_US')
oraz dodać jeden wpis:
INSERT INTO "android_metadata" VALUES ('en_US')
Teraz dla wszystkich tabel należy zmienić klucz główny na _id;
Następnym krokiem jest utworzenie archiwum zip zawierającym jedynie plik z bazą danych. Kopiujemy go do folderu assets, który znajduje się w projekcie naszej aplikacji.
Teraz dodajemy do projektu nową klasę o nazwie: DataHelper, która rozszerza klasę: SQLiteOpenHelper. Do podanej klasy kopiujemy poniższy kod.
package org.axlinux.android;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DataHelper extends SQLiteOpenHelper
{
private static String DATABASE_DIR = "/data/data/org.axlinux.android/databases/"; //Ścieżka do katalogu gdzie przechowywane są bazy danych
private static String DATABASE_NAME = "my_books.sqlite"; //Nazwa pliku z bazą danych
private static String DATABASE_ZIP = "my_books.sqlite.zip"; //Nazwa pliku zip w którym znajduje się skompresowany plik z bazą danych
private SQLiteDatabase db;
private final Context context;
public DataHelper(Context context)
{
super(context, DATABASE_NAME, null, 1);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase arg0)
{
//Implementację tej metody można pominąć
}
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2)
{
//Implementację tej metody można pominąć
}
/**
* Zadaniem metody jest sprawdzenie czy istnieje plik z bazą danych
* @return true jeżeli plik w katalogu istnieje,
* false gdy nie istnieje - nie został jeszcze skopiowany z assets do katalogu w którym android przechowuje pliki baz danych
*/
public boolean dataBaseExists()
{
File f = new File(DATABASE_DIR);
if(!f.exists())
f.mkdir();
boolean result = true;
SQLiteDatabase db_test = null;
try{
db_test = SQLiteDatabase.openDatabase(DATABASE_DIR+DATABASE_NAME, null, SQLiteDatabase.OPEN_READONLY);
} catch (Exception ex){
result = false;
}
if(db_test != null)
db_test.close();
return result;
}
/**
* Metoda rozpakowuje plik z assets do katalogu gdzie Android trzyma bazy danych pod warunkiem, że już nie zostało to zrobione
* @throws IOException
*/
public void copyDataBase() throws IOException
{
if(!this.dataBaseExists())
{
File f = new File(DATABASE_DIR);
if(!f.exists())
f.mkdir();
ZipInputStream zis = new ZipInputStream(context.getAssets().open(DATABASE_ZIP));
ZipEntry entry;
entry = zis.getNextEntry();
int BUFFER = 2048;
FileOutputStream fos = new FileOutputStream(DATABASE_DIR + DATABASE_NAME);
BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
int count;
byte data[] = new byte[BUFFER];
while ((count = zis.read(data, 0, BUFFER)) != -1)
dest.write(data, 0, count);
dest.flush();
dest.close();
zis.close();
}
}
/**
* Metoda otwiera bazę danych, po wywołaniu tej metody można wykonywać polecenie SQL
* @return - true gdy otwarcie się powiodło
*/
public boolean open()
{
boolean result = false;
try{
String myPath = DATABASE_DIR + DATABASE_NAME;
db = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
result = true;
} catch (Exception ex) {
//Otwarcie bazy danych nie powiodło się}
}
return result;
}
public synchronized void close() {
if(db != null)
db.close();
super.close();
}
/**
* Wykonuje zapytanie SQL
* @param query - zapytanie SQL
* @return zwraca Stringa z rezultatem
*/
public String executeQuery(String query)
{
String result = "";
Cursor cursor = db.rawQuery(query, null);
if(cursor.moveToFirst())
{
do
{
result += cursor.getString(0) +". "+ cursor.getString(1) +" "+ cursor.getString(2) +"\n";
}while(cursor.moveToNext());
}
return result;
}
}
Klasa z metodą onCreate rozszerzająca klasę Activity
package org.axlinux.android;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class Main extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String out ="";
TextView tv = (TextView) this.findViewById(R.id.TextView01);
DataHelper dh = new DataHelper(this);
out += "Czy istnieje baza danych? " + dh.dataBaseExists()+"\n";
try
{
dh.copyDataBase();
out += "Czy istnieje baza danych po skopiowaniu? " + dh.dataBaseExists()+"\n";
out +="Rezultat otworzenia bazy danych: " + dh.open()+"\n";
out += "Wynik zapytania \n" + dh.executeQuery("SELECT * FROM books limit 3;");
} catch (Exception ex)
{
out += ex.toString() +"\n";
}
tv.setText(out);
}
}
Pierwszym krokiem po utworzeniu nowej klasy jest modyfikacja pól klasy. Należy odpowiednio zmodyfikować wartości: DATABASE_DIR, DATABASE_NAME, DATABASE_ZIP.
DATABASE_DIR to miejsce gdzie Android przechowuje pliki z bazami danych. Należy poprawnie wprowadzić nazwę głównego pakietu. DATABASE_NAME to nazwa naszej bazy danych, która jest umieszczona wewnątrz archiwum zip, a DATABASE_ZIP to nazwa archiwum z bazą danych w katalogu assets.
W metodzie onCreate możemy teraz stworzyć instancję klasy DataHelper i wywołać metodę copyDataBase. Po zakończeniu warto wywołać metodę dataBaseExists() w celu sprawdzenia rezultatu.
Brak komentarzy:
Prześlij komentarz