Android programmieren: SQL Lite (Teil I)

Mit SQLite liefert uns Android bereits einen vorinstallierten SQL Server für den wir nix mehr tun müssen. Also nicht wie aus der PC Welt üblich: SQL installieren, User anlegen, Rechte definieren etc pp. Sondern unter Android: SQLite ist da. Läuft. Kann verwendet werden. Was auf einem Smartphone oder Tablett PC natürlich auch bedeutet: da greifen jetzt nicht mehrere Benutzer gleichzeitig auf die DB zu, sondern nur einer. Was uns aber SQLite unter Android bringt: Die unter SQLite gespeicherten Informationen werden immer sofort gespeichert und bleiben auch erhalten, wenn sich die Hardware ausschaltet oder die Anwendung beendet wird.

In unserer Anwendung geht es daher nun darum, SQLite unter Android zu verwenden. Es soll eine Textdatei gelesen und in die SQL Datenbank geschrieben werden, es sollen Felder gelesen und Werte geändert (Update) werden. Basis ist eine kleine Artikeldatei mit String-Feldern wie z.B. Artikelnummer, Artikeltext, Lagerort und Menge. Um keine Typkonvertierungen machen zu müssen, sind alle Datenfelder als String ausgelegt, d.h. wenn Mengen in der Anwendung berechnet werden müssen, sind Umwandlungen on String nach Integer / oder Double notwendig. Auf die Anwendung gehen wir nachstehend nicht ein, sondern konzentrieren uns auf den reinen SQL Teil der Software.

Was wir tun müssen:

  • Klasse SQLHelper für die Anwendung erstellen
  • Auf Package: Rechte Maustaste. ProjectDBSQLHelper
  • Datenbase Namen und Grunddaten eintragen. Ebenso Funktion für CREATE TABLE und DROP
  • Achtung: DB wird beim ersten Aufruf von DBHELPER erstellt und nicht mehr geändert! Eine Änderung erfolgt nur, wenn die Versionsnummer erhöht oder die Anwendung deinstalliert wird. (Unbedingt beachten, wenn ihr Felder ändert / löscht oder hinzufügt.)
  • Beispiel findet sich nachfolgend.

Die grundlegenden Definitionen und die Grundroutinen, die Ihr in jedem Fall benötigt folgen nachstehend. Es geht hier um eine DB mit vier String Felder und einem int Wert als Primärschlüssel, damit die Daten schnell lokalisiert werden können.

public class DonxieDBHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "donxiestorage.db";
    private static final int DATABASE_VERSION = 1;
    private static final String TABLE_NAME1 = "data";

    private static final String TAG = "SQLite";

    private static final String TABLE_MOD_CREATE = "CREATE TABLE " + TABLE_NAME1 + " (AID INTEGER PRIMARY KEY, ARTNR TEXT, ARTTXT TEXT, QTY1 TEXT, LOCATION TEXT)";
    private String TABLE_MOD_DEL = "DROP TABLE IF EXISTS " + TABLE_NAME1;

    public DonxieDBHelper(Context context) {
        //------------------------------------------------
        //------------------------------------------------
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        Log.d(TAG, "DbHelper hat die Datenbank: " + getDatabaseName() + " erzeugt.");
    } //


    @Override
    public void onCreate (SQLiteDatabase db) {
        //------------------------------------------------
        //------------------------------------------------

        Log.i(TAG, "MyDatabaseHelper.onCreate ... ");

        try {
            db.execSQL(TABLE_MOD_CREATE);
            Log.d(TAG, "On CreateOK");
        }
        catch (Exception ex) {
            Log.e(TAG, "Fehler beim Anlegen der Tabelle: " + ex.getMessage());
        }
    } //

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

        Log.i(TAG, "MyDatabaseHelper.onUpgrade ... ");

        db.execSQL(TABLE_MOD_DEL);
        onCreate(db);
        Log.d(TAG, "On CreateOK");
    } //


Datensatz einfügen / INSERT

Neuen Datensatz in die SQLite DB einfügen. Es werden alle Datenfelder als String übergeben. Die Funktion ist als void definiert, ermittelt aber den Index des einzufügenden Satzes. Wer mag kann sie daher umbauen, dass sie diesen Index als Returnwert liefert oder halt -1, wenn der Schreibvorgang nicht durchgeführt wurde.

public void insert (String artnr, String arttext, String menge, String location) {
    //------------------------------------------------
    //write 4 string felder into DB
    //------------------------------------------------

    long rowid = -1;

    //Datenbank oeffnen
    SQLiteDatabase db = getWritableDatabase();

    ContentValues values = new ContentValues();
    values.put("ARTNR", artnr);
    values.put("ARTTXT", arttext);
    values.put("QTY1", menge);
    values.put("LOCATION", location);

    rowid = db.insert(TABLE_NAME1, null, values);

    //Log.d("insert", String.valueOf(rowid));
} //

Datensatz Update

Einen Datensatz aktualisieren. Welcher Datensatz wird über Feld index idx festgelegt. Es werden dann Stringfelder zum Aktualisieren übergeben. Ein Return Wert ob es geklappt hat erfolgt nicht. (Könnte man als boolean umbauen und den Erfolg an die Anwendung zurückliefern.)

public void update (int idx, String artnr, String arttext, String menge, String location) {
    //------------------------------------------------
    //Update Record idx mit 4 string felder in DB
    //------------------------------------------------

    String sSQL = "UPDATE " + TABLE_NAME1 + " SET [ARTNR] = '" + artnr + "', [ARTTXT] = '" + arttext + "', [LOCATION] = '" + location + "', [QTY1] = '" + menge + "' WHERE AID=" + idx;

    Log.i(TAG, "Update: " + sSQL);

    SQLiteDatabase db = getWritableDatabase();
    db.execSQL(sSQL);
} //

Datensatz lesen

Einen Datensatz aus der SQLite DB lesen. Als Suchbegriff wird die Artikelnummer verwendet. Rückgabe ist ein Objekt vom Typ Cursor, das in der Anwendung ausgewertet werden kann.

  public Cursor getItem (String myartnr) {
        //------------------------------------------------
        //Read item myartnr from DB. liefert werte in cursor zurueck
        //------------------------------------------------

        // get readable database as we are not inserting anything
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_NAME1 + " WHERE ARTNR = '" + myartnr + "'", null);


/*
                Alternativ gehts auch über Query Abfrage im folgenden Format:
                Cursor cursor = db.query(Note.TABLE_NAME,
                new String[]{Note.COLUMN_ID, Note.COLUMN_NOTE, Note.COLUMN_TIMESTAMP},
                Note.COLUMN_ID + "=?",
                new String[]{String.valueOf(id)}, null, null, null, null);

 */

        if (cursor != null)
            cursor.moveToFirst();

        //cursor.close();
        return cursor;
    } //

 


Anzahl der Datensätze zählen

Die Anzahl der Datensätze in der DB wird ermittelt und von der Routine als int Wert zurück geliefert.

public int CountItems () {
    //------------------------------------------------
    // Anzahl Records in DB zaehlen. Liefert Anazhl als int
    //------------------------------------------------

    SQLiteDatabase db = getWritableDatabase();
    Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_NAME1, null);
    int i = cursor.getCount();
    cursor.close();
    return (i);
} //

Datenbank Inhalt löschen

Alle Daten der SQLite DB in den Müll treten. Am Ende sind alle Daten weg und können neu eingefügt werden. Die Struktur der DB wird nicht verändert.

public void deletedata () {
    //------------------------------------------------
    //------------------------------------------------

    SQLiteDatabase db = getWritableDatabase();
    db.execSQL("delete from "+ TABLE_NAME1);
    Log.i(TAG, "Delete SQL Items");
} //

Datenbank löschen

Die SQLite Tabelle entfernen. Die ist hinterher allerdings völlig futsch und muss neu angelegt werden, bevor sie verwendet und mit Daten gefüllt werden kann. Also eigentlich keine wirklich sinnvolle Sache – aber der Vollständigkeit halber bei mir dabei:

public void deletetable () {
    //------------------------------------------------
    //------------------------------------------------

    SQLiteDatabase db = getWritableDatabase();
    db.execSQL(TABLE_MOD_DEL);
    Log.i(TAG, "Delete Table ... ");
} //

Datenbank exportieren

Hier wollen wir die gesamte SQLite DB in eine TXT Datei exportieren:

public void exportDB(String toFile) {
    //------------------------------------------------
    //Exportiert DB nach Datei.
    //------------------------------------------------

    SQLiteDatabase db = this.getReadableDatabase();

    File dcimDir = null;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
    }

    File myFile = new File (dcimDir, toFile);


    try
    {
        myFile.createNewFile();

        FileWriter fw = new FileWriter(myFile, false);

        Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_NAME1,null);
        //csvWrite.writeNext(curCSV.getColumnNames());
        String data;
        while(cursor.moveToNext())
        {
            String mg1 = cursor.getString(cursor.getColumnIndex("QTY1"));
            mg1 = mg1.replace(".", ",");
            data = cursor.getString(cursor.getColumnIndex("ARTNR")) + ";" + cursor.getString(cursor.getColumnIndex("ARTTXT")) + ";" + mg1 + ";" + cursor.getString(cursor.getColumnIndex("LOCATION"));
            data += "\r\n";
            fw.write(data);

        }
        fw.close();
        cursor.close();
    }
    catch(Exception sqlEx)
    {
        Log.e(TAG, sqlEx.getMessage(), sqlEx);
    }
}

Ich erspare mir jetzt mal, das Ding aufwändig zu kommentieren. Das Meiste ist selbst erklärend und manchmal sind auch noch auskommentierte Optionen im verfügbar, die weitere Hinweise oder Möglichkeiten liefern. Ansonsten gilt: einige Codebeispiele wurden dem Internet entnommen, evtl umgebaut und verwendet. Umfangreiche Quellen kann ich hier (nicht mehr) angeben / liegen nicht vor,+

Es sei noch der Hinweis erlaubt, eine andere Idee unter Android mit derartigen Daten zu arbeiten, wäre die ArryList. Rein subjektiv – Messergebnisse liegen nicht vor – scheint uns die ArryList sogar flinker zu sein, wenn die TXT Datei komplett gelesen oder geschrieben werden soll. Hierbei wäre dann aber zu beachten, dass die Daten aber außerhalb der Anwendung noch gespeichert sein müssen – z.B. via SharedPreferences, was bei SQLite quasi bereits automatisch passiert.


Text und Entwurf. (c) AE SYSTEME Testcenter, Hans-J. Walter
Hans-J. Walter ist Programmierer für Windows DOT.NET / C# und Android und als eingetragener, unabhängiger Journalist verantwortlich für Fachberichte über Technik u. Entwicklung. hjw@terminal-systems.de

Für diese und alle nachfolgenden Seiten gilt ebenso der obligatorische Hinweis: Alle Angaben ohne Gewähr. Bilder und Codes zeigen Beispiele. Diese Beschreibung bezieht sich auf unsere Installation und stellt keine Bewertung der verwendeten Techniken da. Fehler und Irrtümer vorbehalten!