środa, 28 kwietnia 2010

Android a baza danych cz. 2

Tworzenie pliku bazy danych

Można przygotować gotowy plik bazy danych i dystrybuować go razem z aplikacją. Dzięki temu przy pierwszym uruchomieniu nie będzie trzeba czekać wieków na wypełnienie tabel. 

Na początku należy stworzyć plik bazy danych. W tym przypadku korzystamy z sqlite3.exe znajdującego się w AndroidSDK\tools
W konsoli tworzymy bazę danych:

sqlite3.exe database.db

a następnie tworzymy tabele

sqlite>.read create.sql

i wypełniamy danymi

sqlite>.read data.sql

Oczywiście w pliku create.sql jest SQL tworzący tabele, a w data.sql inserty. Trzeba pamiętać o dodaniu tabeli android_metadata - o tym w poprzednim poście. Tak oto przygotowany plik database.db kopiujemy do res/raw naszej aplikacji. Teraz należy sprawić aby przy starcie aplikacji plik bazy został skopiowany do systemu plików androida.

Kopiowanie bazy
Baza danych naszej aplikacji znajduje się na androidzie w katalogu /data/data/nazwa.pakietu/databases/



private static final String DB_PATH ="/data/data/pl.pawelzieba.myapplication/databases/";
private static final int[] dbFiles = {R.raw.database};

void copyDataBase() {
    OutputStream out = null;
    try {
        Log.d(TAG, "Kopiowanie bazy danych ");
        this.getReadableDatabase();
        InputStream in = null;
        out = new FileOutputStream(DB_PATH + DATABASE_NAME);
        byte[] buffer;
        int total = 0;
        for (int i = 0; i < dbFiles.length; i++) {
            try {
                in = mCtx.getResources().openRawResource(dbFiles[i]);
                int size = in.available();
                total += size;
                buffer = new byte[size];
                in.read(buffer);
                out.write(buffer);
            } finally {
                if (in != null)
                    in.close();
            }
        }
        Log.d(TAG, "Kopiowanie zakonczone, calkowity rozmiar pliku bazy danych: " + total);
    } catch (NotFoundException e) {
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (out != null)
                out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


Oczywiście trzeba zadbać o wywołanie tej metody przy pierwszym uruchomieniu aplikacji (poprzedni post). Jeżeli korzystamy z SQLiteOpenHelper to należy zwrócić uwagę na to, że metoda onUpdate(SQLiteDatabase db, int oldVersion, int newVersion) nie będzie działała przy tym rozwiązaniu i trzeba samemu zaimplementować obsługę wersji bazy danych.


Niestety zaprezentowane podejście dalej posiada pewną wadę. Dane wciąż są duplikowane - baza znajduje się w swoim docelowym położeniu i w resources. Jedynym rozwiązaniem wydaje się pobieranie bazy z internetu. 


W następnej części opiszę co zrobić gdy baza danych jest większa niż 1MB.

niedziela, 25 kwietnia 2010

Android a baza danych cz. 1

Wypełanie bazy danych za pomocą SQL
Bardzo przydatną klasą do obsługi bazy danych w Androidzie jest SQLiteOpenHelper, szczególnie przy jej tworzeniu oraz uaktualnianiu. Przy każdym otwarciu jest sprawdzana wersja bazy danych, a jeżeli nie jest utworzona to wywoływana jest metoda onCreate(SQLiteDatabase db), w tym miejscu należy zaimplementować sposób tworzenia bazy.
Na przykład można wykonać SQL tworzący tabele oraz wczytać dane do wypełnienia bazy z pliku data.sql wrzuconego do raw w postaci wielu insertów. Czyli coś w ten deseń:

@Override
public void onCreate(SQLiteDatabase db) {
    Log.d(TAG, "Tworzenie bazy danych");

    db.execSQL(DATABASE_CREATE);
    InputStream in = null;
    try {
        in = mCtx.getResources().openRawResource(R.raw.data);
        if (in != null) {
            InputStreamReader tmp = new InputStreamReader(in);
            BufferedReader reader = new BufferedReader(tmp);
            String str;
            while ((str = reader.readLine()) != null) {
                 db.execSQL(str);
             }
         }
    } catch (java.io.FileNotFoundException e) {
         Log.d(TAG, "FileNotFoundException ",e);
    } catch (IOException e) {
         Log.d(TAG, "IOException ",e);
    } finally {
         try {
             if (in != null){
                 in.close();
             }
         } catch (IOException e) {
             e.printStackTrace();
             Log.d(TAG, "Closing",e);
         }
    }
    Log.d(TAG, "Utworzono baze danych");
}


Należy pamiętać o dodaniu tabeli android_metadata.


CREATE TABLE "android_metadata" ("locale" TEXT DEFAULT 'en_US');


i wstawienie wartości


INSERT INTO "android_metadata" VALUES ('en_US');


Jeśli chodzi o niewielkie bazy danych to ok, ale co gdy mamy do czynienia z większą ilością danych, gdy plik data.sql ma około kilka MB. Wtedy po pierwsze android nie otworzy pliku większego niż 1MB (takie systemowe ograniczenie), po drugie wykonywanie tych wszystkich insertów będzie trochę trwało, a po trzecie aplikacja będzie zajmowała więcej miejsca na telefonie niż naprawdę potrzebuje ponieważ dane się duplikują w pliku data.sql oraz w bazie danych. Niestety nie da się skasować pliku dodanego do aplikacji ponieważ plik apk jest podpisany cyfrowo.
Jeśli chodzi o pierwszy problem to plik można zawsze podzielić na kilka mniejszych tak aby nie przekraczały 1MB. W drugim przypadku możemy się pocieszyć, że wrzucanie danych następuje tylko przy pierwszym uruchomieniu, potem aplikacja startuje normalnie. Natomiast użytkownik mając niewiele miejsca na telefonie na początku wykasuje aplikacje zajmujące najwięcej miejsca, dlatego lepiej unikać duplikacji niepotrzebnych rzeczy.
Warto więc zastanowić się nad innym rozwiązaniem. W następnej części przedstawię jak można dodać do aplikacji już gotową bazę danych.


piątek, 23 kwietnia 2010

Android na iPhonie

Ta wiadomość:
http://linuxoniphone.blogspot.com/2010/04/ive-been-working-on-this-quietly-in.html
sprawiła, że cały dzień chce mi się śmiać.

Koniec świata. Android na iPhonie!
Wreszcie pojawiła się wspólna platforma na której można porównać oba systemy, hehe.
Są jeszcze pewne problemy, ale jak zostaną rozwiązane to myślę, że takie porównanie wyjdzie na dobre obu systemom. Mam nadzieję, że wytworzy się atmosfera sprzyjająca merytorycznej dyskusji bez możliwości zrzucania winy na hardware itp.