android sqlite introT7_wowomnom_Fotolia_85154667

Android SQLite Datenbank Tutorial – Teil 7: Datensätze in der SQLite Datenbank ändern


Bevor wir jedoch mit dem Programmieren beginnen, werden wir uns im theoretischen Teil dieser Android Lektion intensiver mit der Contextual Action Bar beschäftigen und Dialoge in Android kennenlernen.

Nun wünschen wir euch viel Spaß bei Teil 7 unseres Android SQLite Datenbank Tutorials. Los geht’s!

1. Daten in der SQLite Datenbank mit Hilfe der Contextual Action Bar ändern

In diesem Abschnitt werden wir den SQL-Befehl update(), der für das Ändern von Datensätzen verantwortlich ist, näher kennenlernen.

Zusätzlich werden wir auf die Callback-Methoden der Contextual Action Bar detailliert eingehen. Dabei erfahren wir welche Callback-Methode für welche Aufgabe benötigt wird. Die Contextual Action Bar haben wir bereits in der vorherigen Lektion kennengelernt und in unsere SQLite App integriert.

1.1 Daten in der SQLite Datenbank ändern

Das Ändern von Datensätzen in einer SQLite Datenbank ist sehr einfach. Die neuen Daten werden in ContentValues zwischengespeichert und dann mit der Methode update() in die SQLite Datenbank eingetragen.

Folgender Quellcode stellt dies beispielhaft dar:

ContentValues values = new ContentValues();
values.put(ShoppingMemoDbHelper.COLUMN_PRODUCT, newProduct);
values.put(ShoppingMemoDbHelper.COLUMN_QUANTITY, newQuantity);

database.update(ShoppingMemoDbHelper.TABLE_SHOPPING_LIST,
                values,
                ShoppingMemoDbHelper.COLUMN_ID + "=" + id,
                null);

In den Zeilen 1 bis 3 bereiten wir die geänderten Werte für das Eintragen in die SQLite Datenbank vor. Dazu erzeugen wir ein ContentValues-Objekt und fügen die neuen Werte für das Produkt und die Anzahl darin ein.

Das Eintragen übernimmt die put() Methode, der wir jeweils ein Schlüssel-Wert Paar (Key-Value Pair) übergeben. Der Schlüssel muss dabei dem Name der entsprechenden Spalte unserer Tabelle entsprechen.

Anschließend aktualisieren wir die Werte des entsprechenden Datensatzes mit Hilfe der update() Methode, die wir auf dem SQLiteDatabase-Objekt aufrufen. Sie erwartet als Argumente den Namen der Tabelle, das ContentValues-Objekt und das Suchkriterium, in unserem Fall der Datensatz mit der bestimmten ID. Das letzte Argument wird nicht benötigt und ist daher null.

plhq_teaser_hbox_gelb_fotolia_RA Studio_46292813

Unser großes
Android Online-Kurs
Gesamtpaket



Weitere Infos

Wie in den vorherigen Lektionen schon mehrfach erwähnt, werden alle Zugriffe auf die SQLite Datenbank von unserer Datenquelle verwaltet. Daher werden wir die oberen Quellcode-Zeilen später in der neuen Methode updateShoppingMemo() der ShoppingMemoDataSource-Klasse wiederverwenden.

1.2 Die Callbacks der Contextual Action Bar

Die Contextual Action Bar haben wir bereits in der vorherigen Lektion kennengelernt. Um sie zu initialisieren, müssen die folgenden fünf Callback-Methoden implementiert werden:

  • onItemCheckedStateChanged() – Wird aufgerufen, wenn ein Listeneintrag aus- oder abgewählt wird. Hier zählen wir die ausgewählten Einträge mit und fordern mode.invalidate() an, um die Contextual Action Bar anzupassen.
  • onCreateActionMode() – Wird aufgerufen, wenn der Action Mode erzeugt wird. Hier füllen wir das Menü der Contextual Action Bar mit Action Items.
  • onPrepareActionMode() – Wird immer dann aufgerufen, wenn der Action Mode gezeigt wird. Wird immer nach onCreateActionMode() aufgerufen und kann auch mehrfach aufgerufen werden, z.B. wenn der Action Mode ungültig geworden ist. Hier reagieren wir auf die invalidate() Anfrage und passen die Contextual Action Bar entsprechend den Erfordernissen an.
  • onActionItemClicked() – Wird aufgerufen, wenn der User einen Menüeintrag der Contextual Action Bar angeklickt hat. Hier reagieren wir auf Klicks auf die Menüeinträge.
  • onDestroyActionMode() – Wird aufgerufen, wenn der User den Action Mode verlässt. Hier setzen wir den Zähler, der anzeigt wie viele Einträge ausgewählt sind, wieder zurück.

Der folgende Quellcode enthält die fünf Callback-Methoden der Contextual Action Bar mit kurzen Erläuterungen:

final ListView shoppingMemosListView = (ListView) findViewById(R.id.listview_shopping_memos);
shoppingMemosListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);

shoppingMemosListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {

    @Override
    public void onItemCheckedStateChanged(ActionMode mode, int position, 
                                          long id, boolean checked) {
        // Hier zählen wir mit wie viele Einträge ausgewählt sind.
        // Von hier fordern wir ein mode.invalidate() an, um die CAB anzupassen.
    }

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        // Das Menü der CAB mit Actions füllen.
        getMenuInflater().inflate(R.menu.menu_contextual_action_bar, menu);
        return true;
    }

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        // Hier passen wir die CAB an, indem wir auf die invalidate() Anfrage reagieren.
        // Wir ändern hier den Text und die angezeigten Menü-Symbole der CAB.
        return false;
    }

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        // Hier reagieren wir auf Klicks auf CAB-Actions.
        switch (item.getItemId()) {
            case R.id.cab_delete:
                deleteSelectedItems(); // Einträge löschen
                mode.finish();         // und CAB schließen.
                return true;
            case R.id.cab_update:
                updateSelectedItem(); // Eintrag ändern
                mode.finish();         // und CAB schließen.
                return true;
            default:
                return false;
        }
    }

    @Override
    public void onDestroyActionMode(ActionMode mode) {
        // Wir setzen hier den Zähler wieder auf Null.
    }
});

Um mit Hilfe der Contextual Action Bar Datensätze in der SQLite Datenbank ändern zu können, werden wir an vier der fünf Callback-Methoden Änderungen vornehmen. Im oberen Quellcode haben wir in den Kommentaren kurz beschrieben, was wir in dem jeweiligen Callback durchführen werden.

Was wir in den Callbacks genau machen, werden wir in einem späteren Abschnitt dieser Lektion noch detailliert beschreiben. Im Moment ist es aber ausreichend zu wissen, dass es die Callback-Methoden gibt und was ihre Funktion ist.

2. Einen AlertDialog in Android erstellen

Android Apps Programmieren Online-Kurs

Unser großes
Android Online-Kurs
Gesamtpaket



Weitere Infos

Ein Dialog ist ein kleines Fenster, welches dem Benutzer eingeblendet wird, um eine Entscheidung zu treffen oder zusätzliche Informationen einzugeben.

Dialoge füllen den Bildschirm des Android Geräts meist nicht vollständig aus. Der User soll mit ihrer Hilfe oft eine einfache Aktion ausführen können, bevor die Anwendung wieder fortgesetzt werden kann.

Die Klasse Dialog ist die Basisklasse für Dialoge, sie sollte jedoch nicht instanziiert werden. Stattdessen sollte mit einer ihrer Subklassen gearbeitet werden.

In Android werden folgende Dialog-Subklassen oft verwendet:

  • AlertDialog – Mit dieser Klasse kann ein Dialog mit einem Titel, bis zu drei Buttons, einer Liste oder auch einem eigenen Layout dargestellt werden. Wir werden für unsere SQLite App einen AlertDialog erzeugen.
  • DatePickerDialog – Mit dieser Klasse kann ein vordefinierter Dialog zur Datumswahl angezeigt werden.
  • TimePickerDialog – Mit dieser Klasse kann ein vordefinierter Dialog zur Zeitauswahl angezeigt werden.

Diese Klassen definieren das Aussehen und den Aufbau für den eigenen Dialog. Sie können sogar zusätzlich in einem DialogFragment eingebettet werden, wodurch Lifecycle Events, wie Pressen des Back-Buttons oder Rotieren des Bildschirms, korrekt behandelt werden können.

Wir werden dies in diesem SQLite Tutorial jedoch nicht tun, sondern direkt mit der AlertDialog-Klasse arbeiten. Wir tun dies, damit unser Android Projekt nicht zu groß und komplex wird. Wie wir später sehen werden, wird unsere Lösung wie erwartet funktionieren. Das Verwenden der DialogFragment-Klasse wäre aber die sauberere Lösung.

2.1 Wie wird ein AlertDialog in Android erstellt?

Mit der AlertDialog-Klasse können viele verschiedene Dialog-Designs nachgebildet werden. Die Dialoge werden mit dem AlertDialog.Builder zusammengebaut und bestehen immer aus drei Bereichen.

Ein AlertDialog besteht aus den folgenden drei Bereichen:

  1. Titel-Bereich – Der oberste Bereich ist für den Titel des Dialogs vorgesehen. Dieser Bereich ist optional und sollte nur wenn nötig verwendet werden, bspw. über einer Liste oder einem eigenen Layout.
  2. Inhalt-Bereich – Der mittlere Bereich enthält den Inhalt des Dialogs. Hier kann eine Nachricht, eine Liste oder ein komplettes Layout mit verschiedenen Widget-Elementen angezeigt werden.
  3. Action Button-Bereich – Im unteren Bereich befinden sich immer die Buttons. Neben einem positiven (Agree) und negativen (Cancel) Button kann auch ein neutraler (Remind me later) Button angezeigt werden.

Mit der AlertDialog.Builder-Klasse können diese Bereiche erstellt werden. Diese Klasse stellt die API zur Verfügung und ermöglicht einen bequemen und schnellen Zusammenbau von Dialogen.

Um einen kompletten AlertDialog zu erzeugen, geht man wie folgt vor:

// 1. Erzeugen eines AlertDialog.Builder Objekts mit dem Konstruktor
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

// 2. Aneinanderreihen mehrerer Setter-Methoden um den Dialog zu bauen
builder.setMessage(R.string.dialog_message)
       .setTitle(R.string.dialog_title);

// 3. Erzeugen des AlertDialogs mit der create() Methode
AlertDialog dialog = builder.create();

// 4. Anzeigen des AlertDialogs mit der show() Methode
dialog.show();

2.2 Einem AlertDialog Buttons hinzufügen

In Android können einem Dialog mit Hilfe des AlertDialog.Builders sehr einfach Buttons hinzugefügt werden. Für die eingefügten Buttons können auch direkt Listener registriert werden.

Um Buttons in einem Dialog einzufügen, geht man folgendermaßen vor:

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

// Hinzufügen der Buttons
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // OK-Button wurde geklickt. Hier reagieren wir auf den Klick. 
           }
       });
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // CANCEL-Button wurde geklickt. Hier reagieren wir auf den Klick.
           }
       });
builder.setNeutralButton(R.string.neutral, new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // NEUTRAL-Button wurde geklickt. Hier reagieren wir auf den Klick.
           }
       });

Mit den drei Methoden setPositiveButton(), setNegativeButton() und setNeutralButton() werden die Buttons für positives, negatives und neutrales Feedback erstellt. Sie erwarten als Argumente den Button-Titel als String und einen DialogInterface.OnClickListener mit dem auf Klicks reagiert werden kann.

Die verschiedenen Button Arten sollten wie folgt eingesetzt werden:

  • Positive Button – Geplante Aktionen sollten fortgesetzt oder vorgenommene Eingaben akzeptiert werden.
  • Negative Button – Geplante Aktionen sollten abgebrochen werden.
  • Neutral Button – Geplante Aktionen sollten weder abgebrochen noch fortgesetzt werden. Sie sollten nur auf eventuell später verschoben werden. Ein bekanntes Beispiel hierfür ist der Remind me later. Button.

Einem AlertDialog kann nur ein Button jeder Button-Art zugewiesen werden. Es kann somit keine zwei Positive Buttons in einem Dialog geben.

Wir werden unserem AlertDialog einen positiven und einen negativen Button hinzufügen. Einen neutralen Dialog werden wir nicht benötigen.

2.3 Einem AlertDialog ein eigenes Layout zuweisen

Mit unserem AlertDialog sollen Änderungen an einem Datensatz der SQLite Datenbank vorgenommen werden können.

Dazu müssen wir die Eingaben der User erfassen können und benötigen somit ein eigenes Layout mit zwei EditText-Feldern.

Zum Glück haben die Entwickler von Android schon an einen solchen Fall gedacht und mit der Methode setView() das passende Werkzeug für uns zur Verfügung gestellt.

Um einen Dialog mit einem eigenen Layout zu erstellen wird wieder der AlertDialog.Builder benötigt, auf dessen Instanz die Methode setView() aufgerufen werden muss. Als Argument muss ein View-Objekt übergeben werden.

Das View-Objekt können wir nach unseren Vorstellungen erstellen. Alles was wir dafür benötigen ist eine Layout-Ressourcen Datei, in der wir das gewünschte Layout des Dialogs definieren.

Um einen AlertDialog ein eigenes Layout zuzuweisen, geht man wie folgt vor:

// AlertDialog.Builder Objekt erzeugen
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

// Den LayoutInflater anfragen
LayoutInflater inflater = getActivity().getLayoutInflater();

// Den View des Dialogs mit dem Elementen der Layout-Ressourcen Datei füllen
View dialogsView = inflater.inflate(R.layout.dialog_edit_memo, null);

// Dem AlertDialog den View hinzufügen
builder.setView(dialogsView)

// Das AlertDialog Objekt erzeugen und anzeigen
AlertDialog editMemoDialog = builder.create();
editMemoDialog.show();

Standardmäßig füllt das so zugewiesene Layout das Dialogfenster aus. Es können zudem weitere Elemente, wie ein Titel oder Buttons, dem AlertDialog mit dem Hilfe der Setter-Methoden des AlertDialog.Builders zugewiesen werden.

Wie das Erstellen und Nutzen eines AlertDialogs in der Praxis funktioniert, werden wir später in Abschnitt 6 erfahren, wenn wir unseren eigenen AlertDialog implementieren.

3. Action Item für die Contextual Action Bar definieren

Wir haben jetzt den theoretischen Teil dieser Lektion abgeschlossen und werden nun das Gelernte in die Praxis umsetzen.

Mit unserer Android App soll es möglich sein, Änderungen an den Einträge der SQLite Datenbank mit Hilfe der Contextual Action Bar vorzunehmen. Dazu wird ein weiterer Action Item („Eintrag ändern“) benötigt, den wir nun als neuen Menüeintrag in der XML-Menü Datei unseres Android Projekts definieren werden.

Wir öffnen dazu die menu_contextual_action_bar.xml XML-Menü Datei in dem Editor von Android Studio. Sie befindet sich im Ressourcen-Ordner res/menu/ unseres Android Projekts.

Wir fügen nun den markierten XML-Code in die menu_contextual_action_bar.xml Datei direkt oberhalb des bisherigen Menüeintrags ein:

menu_contextual_action_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/cab_change"
        android:icon="@android:drawable/ic_menu_edit"
        android:title="@string/cab_change" />

    <item
        android:id="@+id/cab_delete"
        android:icon="@android:drawable/ic_menu_delete"
        android:title="@string/cab_delete" />

</menu>

Mit dem oberen Code haben wir das Menü der Contextual Action Bar um einen Eintrag erweitert.

Das Menü besteht aus zwei Menüeinträgen (item). Für den neuen Menüeintrag haben wir mit @+id/cab_change eine eigene ID angelegt. Weiterhin haben wir als Symbol für den Menüeintrag einen Stift festgelegt.

In Zeile 7 greifen wir auf die String-Ressource @string/cab_change zu und verwenden diese als Titel des Ändern-Menüeintrags.

In Android Studio sollte die menu_contextual_action_bar.xml Datei nun wie folgt aussehen:

android_sqlite_update_cab

Definieren des zweiten Action Items für das Menü der Contextual Action Bar

Wir haben jetzt einen zweiten Action Item in der XML-Menü Datei für die Contextual Action Bar definiert. Dabei greifen wir auch auf die Ressourcen-Datei strings.xml zurück und lesen aus ihr die Bezeichnung für unseren Menüeintrag (Ändern-Aktion) aus.

Als Nächstes werden wir das Layout für den AlertDialog definieren und dazu eine neue Layout-Datei erstellen.

4. Erstellen einer Layout-Datei für den AlertDialog

Den Menüeintrag für das Ändern der SQLite Datenbank Daten haben wir nun erstellt. Als Nächstes benötigen wir das XML-Layout für den AlertDialog, über den die Änderungen an den Daten vorgenommen werden können.

Wir werden nun ein solches Layout Resource File in Android Studio anlegen und darin das Layout für den AlertDialog definieren. Die zu erstellende XML-Layout Datei muss in dem res/layout/ Ressourcen-Ordner abgelegt werden.

Wir führen nun die folgenden Schritte aus:

  1. Zunächst mit der rechten Maustaste auf den layout/ Ordner klicken.
  2. Anschließend den Eintrag New des Kontext-Menüs anklicken.
  3. Und schließlich auf Layout resource file klicken.
android_sqlite_update_layout_create

Erstellen des Layout Resource File dialog_edit_shopping_memo.xml für den AlertDialog unserer App

Anschließend öffnet sich der New Layout Resource File-Dialog, der uns bei der Erstellung der XML-Ressourcen Datei unterstützt. Wir füllen nun die beiden Felder des Dialogs aus.

In dem New Layout Resource File-Dialog nehmen wir nun die folgenden Einstellungen vor:

  1. Als Dateinamen tragen wir in das Feld File name dialog_edit_shopping_memo.xml ein.
  2. Den Wert für das Root element (Wurzelelement des UI-Layouts) lassen wir auf LinearLayout stehen.
android_sqlite_update_layout_name

Dateinamen und das Wurzelelement für die neue XML-Layout Datei vorgeben

Anschließend bestätigen wir den New Layout Resource File-Dialog mit einem Klick auf den OK Button, woraufhin die neue XML-Ressourcen Datei automatisch von Android Studio erstellt und im Editorfenster der IDE geöffnet wird.

Falls die Datei nicht automatisch geöffnet wurde, führen wir das Öffnen manuell durch. Dazu klicken wir doppelt auf ihren Dateinamen dialog_edit_shopping_memo.xml im Project Tool Window von Android Studio. Die Datei befindet sich im res/layout/ Ordner unseres Projekts.

Standardmäßig öffnet sich das Editorfenster in der Design-Ansicht. Damit der XML-Code der Layout Datei angezeigt wird, müssen wir unten im Editorfenster den Tab Text anklicken.

Der AlertDialog unserer Android App soll im Mittelteil zwei EditText-Widgets (Anzahl und Produkt) mit zugehörigen TextViews enthalten. Über die EditText-Felder sollen die Benutzer später die Datenbankeinträge ändern können.

Um das eben besprochene Layout zu erstellen, löschen wir nun den generierten XML-Code vollständig und fügen an dessen Stelle den folgenden XML-Code ein:

dialog_edit_shopping_memo.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusableInTouchMode="true">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10sp">
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="@string/dialog_title_quantity"
            android:layout_weight="1"
            android:gravity="end"
            android:layout_marginEnd="5sp" />
        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:inputType="number"
            android:layout_weight="3"
            android:id="@+id/editText_new_quantity" />
    </LinearLayout>

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="@string/dialog_title_product"
            android:layout_weight="1"
            android:gravity="end"
            android:layout_marginEnd="5sp" />
        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:inputType="text"
            android:layout_weight="3"
            android:id="@+id/editText_new_product" />
    </LinearLayout>

</LinearLayout>

Mit dem oberen Quellcode definieren wir das UI-Layout für unseren AlertDialog. Die visuelle Struktur besteht aus mehreren View-Elementen. Als Wurzelelement besitzt das XML-Layout ein LinearLayout-Element, welches die anderen UI-Elemente in sich aufnimmt.

Das LinearLayout-Wurzelelement enthält zwei innere LinearLayout-Elemente, die jeweils ein TextView– und ein EditText-Element enthalten. Über die EditText-Felder werden die Benutzer in unserer SQLite App die Änderungen an einem Listeneintrag vornehmen können. Dabei wird auch der zugrunde liegende Datensatz geändert werden.

Aus der XML-Layout Datei werden wir später ein View-Objekt erzeugen und dieses dann dem AlertDialog mit der Methode setView() zuweisen. Das erstellte Layout wird den mittleren Bereich des AlertDialogs ausfüllen.

In Android Studio sollte die dialog_edit_shopping_memo.xml Datei nun wie folgt aussehen:

android_sqlite_update_layout_code

Die XML-Layout Datei dialog_edit_shopping_memo.xml mit den vorgenommenen Änderungen

Wir haben jetzt ein XML-Layout für den AlertDialog erstellt. Dabei greifen wir auch auf die Ressourcen-Datei strings.xml zurück und lesen aus ihr die Bezeichnungen für die beiden TextViews aus.

Den AlertDialog werden wir später in Abschnitt 6 in der MainActivity-Klasse initialisieren. Doch vorher werden wir eine Methode zum Ändern von Datensätzen in der SQLite Datenbank erstellen. Die neue Methode werden wir in unserer Datenquelle der ShoppingMemoDataSource-Klasse definieren.

5. Die updateShoppingMemo() Methode in unserer Datenquelle ShoppingMemoDataSource anlegen

Das Ändern von Datensätzen werden wir von unserer Datenquelle ausführen lassen. Dazu werden wir die Methode updateShoppingMemo() in die Klasse ShoppingMemoDataSource einfügen. Import-Anweisungen werden wir dafür nicht benötigen.

Hinweis: Wir werden jetzt die Arbeitsschritte der Reihe nach ausführen. Sollte etwas unklar sein, könnt ihr im Anschluss daran den gesamten Quellcode der ShoppingMemoDataSource-Klasse in Ruhe analysieren und direkt erkennen, an welcher Stelle welcher Code-Block eingefügt werden muss.

5.1 Die Methode updateShoppingMemo() definieren

Wir öffnen nun die Klassendatei ShoppingMemoDataSource.java in dem Editor von Android Studio. Die Klassendatei befindet sich im Package-Ordner de.codeyourapp.shoppinglist unseres Projekts.

Wir fügen nun den folgenden Quellcode in den Methodenbereich der ShoppingMemoDataSource-Klasse direkt nach der deleteShoppingMemo() Methode ein:

ShoppingMemoDataSource.java

public ShoppingMemo updateShoppingMemo(long id, String newProduct, int newQuantity) {
    ContentValues values = new ContentValues();
    values.put(ShoppingMemoDbHelper.COLUMN_PRODUCT, newProduct);
    values.put(ShoppingMemoDbHelper.COLUMN_QUANTITY, newQuantity);

    database.update(ShoppingMemoDbHelper.TABLE_SHOPPING_LIST,
                    values,
                    ShoppingMemoDbHelper.COLUMN_ID + "=" + id,
                    null);

    Cursor cursor = database.query(ShoppingMemoDbHelper.TABLE_SHOPPING_LIST,
                columns, ShoppingMemoDbHelper.COLUMN_ID + "=" + id,
                null, null, null, null);

    cursor.moveToFirst();
    ShoppingMemo shoppingMemo = cursorToShoppingMemo(cursor);
    cursor.close();

    return shoppingMemo;
}

Das Ändern von Datensätzen in einer SQLite Datenbank ist sehr einfach. Als Erstes erzeugt man ein ContentValues-Objekt und füllt dieses mit den benötigten Schlüssel-Werte Paaren (Key-Value Pairs), wie in den Zeilen 2 bis 4 dargestellt. Der Schlüssel ist dabei immer der Name der entsprechenden Spalte und der Wert entspricht dem neuen Inhalt.

Mit der Anweisung in Zeile 6 bis 9 wird der entsprechende Datensatz geändert. Dazu wird die update() Methode auf dem SQLiteDatabase-Objekt aufgerufen. Als Argumente übergeben wir den Tabellennamen, das ContentValues-Objekt und das Suchkriterium, hier die ID des zu ändernden Datensatzes. Das vierte Argument wird nicht benötigt und ist daher null.

Mit den restlichen Zeilen lesen wir den eben abgeänderten Datensatz wieder aus und erzeugen daraus ein ShoppingMemo-Objekt, welches wir am Ende der Methode als Rückgabewert der aufrufenden Methode übergeben.

5.2 Der komplette Quellcode der ShoppingMemoDataSource-Klasse

Nun haben wir die neue Methode updateShoppingMemo() in der ShoppingMemoDataSource-Klasse definiert und das Ändern von Datensätzen in der Tabelle der Android SQLite Datenbank vorbereitet.

In dem unten angegebenen Quellcode ist die gesamte ShoppingMemoDataSource-Klasse zur Kontrolle für euch aufgeführt. Die neu eingefügten Zeilen sind markiert worden.

Der vollständiger Quelltext der Klasse ShoppingMemoDataSource.java:

ShoppingMemoDataSource.java

package de.codeyourapp.shoppinglist;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import android.content.ContentValues;
import android.database.Cursor;
import java.util.ArrayList;
import java.util.List;

public class ShoppingMemoDataSource {

    private static final String LOG_TAG = ShoppingMemoDataSource.class.getSimpleName();

    private SQLiteDatabase database;
    private ShoppingMemoDbHelper dbHelper;

    private String[] columns = {
            ShoppingMemoDbHelper.COLUMN_ID,
            ShoppingMemoDbHelper.COLUMN_PRODUCT,
            ShoppingMemoDbHelper.COLUMN_QUANTITY
    };

    public ShoppingMemoDataSource(Context context) {
        Log.d(LOG_TAG, "Unsere DataSource erzeugt jetzt den dbHelper.");
        dbHelper = new ShoppingMemoDbHelper(context);
    }

    public void open() {
        Log.d(LOG_TAG, "Eine Referenz auf die Datenbank wird jetzt angefragt.");
        database = dbHelper.getWritableDatabase();
        Log.d(LOG_TAG, "Datenbank-Referenz erhalten. Pfad zur Datenbank: " + database.getPath());
    }

    public void close() {
        dbHelper.close();
        Log.d(LOG_TAG, "Datenbank mit Hilfe des DbHelpers geschlossen.");
    }

    public ShoppingMemo createShoppingMemo(String product, int quantity) {
        ContentValues values = new ContentValues();
        values.put(ShoppingMemoDbHelper.COLUMN_PRODUCT, product);
        values.put(ShoppingMemoDbHelper.COLUMN_QUANTITY, quantity);

        long insertId = database.insert(ShoppingMemoDbHelper.TABLE_SHOPPING_LIST, null, values);

        Cursor cursor = database.query(ShoppingMemoDbHelper.TABLE_SHOPPING_LIST,
                columns, ShoppingMemoDbHelper.COLUMN_ID + "=" + insertId,
                null, null, null, null);

        cursor.moveToFirst();
        ShoppingMemo shoppingMemo = cursorToShoppingMemo(cursor);
        cursor.close();

        return shoppingMemo;
    }

    public void deleteShoppingMemo(ShoppingMemo shoppingMemo) {
        long id = shoppingMemo.getId();

        database.delete(ShoppingMemoDbHelper.TABLE_SHOPPING_LIST,
                ShoppingMemoDbHelper.COLUMN_ID + "=" + id,
                null);

        Log.d(LOG_TAG, "Eintrag gelöscht! ID: " + id + " Inhalt: " + shoppingMemo.toString());
    }

    public ShoppingMemo updateShoppingMemo(long id, String newProduct, int newQuantity) {
        ContentValues values = new ContentValues();
        values.put(ShoppingMemoDbHelper.COLUMN_PRODUCT, newProduct);
        values.put(ShoppingMemoDbHelper.COLUMN_QUANTITY, newQuantity);

        database.update(ShoppingMemoDbHelper.TABLE_SHOPPING_LIST,
                values,
                ShoppingMemoDbHelper.COLUMN_ID + "=" + id,
                null);

        Cursor cursor = database.query(ShoppingMemoDbHelper.TABLE_SHOPPING_LIST,
                columns, ShoppingMemoDbHelper.COLUMN_ID + "=" + id,
                null, null, null, null);

        cursor.moveToFirst();
        ShoppingMemo shoppingMemo = cursorToShoppingMemo(cursor);
        cursor.close();

        return shoppingMemo;
    }

    private ShoppingMemo cursorToShoppingMemo(Cursor cursor) {
        int idIndex = cursor.getColumnIndex(ShoppingMemoDbHelper.COLUMN_ID);
        int idProduct = cursor.getColumnIndex(ShoppingMemoDbHelper.COLUMN_PRODUCT);
        int idQuantity = cursor.getColumnIndex(ShoppingMemoDbHelper.COLUMN_QUANTITY);

        String product = cursor.getString(idProduct);
        int quantity = cursor.getInt(idQuantity);
        long id = cursor.getLong(idIndex);

        ShoppingMemo shoppingMemo = new ShoppingMemo(product, quantity, id);

        return shoppingMemo;
    }

    public List<ShoppingMemo> getAllShoppingMemos() {
        List<ShoppingMemo> shoppingMemoList = new ArrayList<>();

        Cursor cursor = database.query(ShoppingMemoDbHelper.TABLE_SHOPPING_LIST,
                columns, null, null, null, null, null);

        cursor.moveToFirst();
        ShoppingMemo shoppingMemo;

        while(!cursor.isAfterLast()) {
            shoppingMemo = cursorToShoppingMemo(cursor);
            shoppingMemoList.add(shoppingMemo);
            Log.d(LOG_TAG, "ID: " + shoppingMemo.getId() + ", Inhalt: " + shoppingMemo.toString());
            cursor.moveToNext();
        }

        cursor.close();

        return shoppingMemoList;
    }

}

Vergleicht bitte ganz genau den oberen Quellcode mit eurem eigenen Quellcode in Android Studio. Es ist wichtig, dass ihr die markierten Änderungen an exakt den gleichen Stellen im Quelltext der ShoppingMemoDataSource-Klasse durchgeführt habt.

In Android Studio sollte die ShoppingMemoDataSource.java Klassendatei nun wie folgt aussehen:

android_sqlite_update_datasource

Die Klassendatei ShoppingMemoDataSource.java mit den vorgenommenen Änderungen

In der oberen Abbildung ist die ShoppingMemoDataSource.java Klassendatei dargestellt. Es ist nur die hinzugefügte Methode updateShoppingMemo() aufgeklappt. Alle anderen Methoden sind unverändert geblieben und daher zugeklappt. Die hinzugefügten Codezeilen sind zudem mit Markierungen versehen worden.

Durch neue Methode updateShoppingMemo() (Markierung A) können wir nun Datensätze in der SQLite Datenbank ändern lassen. Wir werden sie bereits im nächsten Abschnitt nutzen und erstmals Datensätze in unserer SQLite Datenbank ändern.

Dafür werden wir die Contextual Action Bar verwenden und über deren Action Item (Ändern-Aktion) mehrere Einträge des ListView und gleichzeitig auch der SQLite Datenbank ändern. Über den neuen Action Item werden wir unseren, in dieser Lektion definierten, AlertDialog aufrufen und durch ihn die Eingaben der Benutzer erfassen.

6. Die Contextual Action Bar in der MainActivity erweitern

Nun werden wir die Contextual Action Bar in der MainActivity-Klasse erweitern. Dazu werden wir die MainActivity um eine neue Methode erweitern, mit der wir einen AlertDialog erstellen lassen. Mit Hilfe der Contextual Action Bar und dem AlertDialog wird es möglich sein, Datensätze der SQLite Datenbank zu ändern.

Um dies zu realisieren, nehmen wir die folgenden Änderungen am Quellcode der Klasse MainActivity vor:

  1. Einfügen der Import-Anweisungen – Zuerst importieren wir die benötigten Klassen und Interfaces.
  2. Definieren der createEditShoppingMemoDialog() Methode – Diese Methode wird den AlertDialog erstellen, mit dem wir Änderungen an den Datensätzen der SQLite Datenbank vornehmen können.
  3. Erweitern der initializeContextualActionBar() Methode – In dieser Methode haben wir einen MultiChoiceModeListener für den ListView registriert und somit die Contextual Action Bar initialisiert. Wir erweitern nun die Callback-Methoden der Contextual Action Bar, um Einträge des ListViews und gleichzeitig auch der hinterlegten SQLite Datenbank ändern zu können. Die Eingabe der neuen Werte erfassen wir mit einem AlertDialog, den wir über die Contextual Action Bar aufrufen werden.

Hinweis: Wir werden jetzt die Arbeitsschritte der Reihe nach ausführen. Sollte etwas unklar sein, könnt ihr im Anschluss daran den gesamten Quellcode der MainActivity-Klasse in Ruhe analysieren und direkt erkennen, an welcher Stelle welcher Code-Block eingefügt werden muss.

Nun beginnen wir mit dem ersten Arbeitsschritt.

6.1 Einfügen der Import-Anweisungen

Wir öffnen nun die Klassendatei MainActivity.java in dem Editor von Android Studio. Die Klassendatei befindet sich im Package-Ordner de.codeyourapp.shoppinglist unseres Projekts.

Anschließend fügen wir den folgenden Quellcode unter den bereits vorhandenen Import-Anweisungen ein:

MainActivity.java

import android.content.DialogInterface;
import androidx.appcompat.app.AlertDialog;
import android.view.LayoutInflater;

Die drei Klassen bzw. Interfaces machen wir mittels Import-Anweisungen innerhalb der Klasse MainActivity sichtbar, so dass wir sie ohne den Namen ihres Packages verwenden können.

Das Interface DialogInterface benötigen wir für das Implementieren der OnClickListener() der AlertDialog-Buttons. Die Klassen AlertDialog und LayoutInflater werden für den AlertDialog selbst bzw. für Erzeugen der UI-Elemente des Dialogs benötigt.

6.2 Definieren der createEditShoppingMemoDialog() Methode

Im zweiten Arbeitsschritt definieren wir die Methode createEditShoppingMemoDialog(), die für uns den AlertDialog erstellen wird. Die neue Methode erstellt ein AlertDialog-Objekt und gibt es anschließend an die aufrufende Methode zurück.

Wir fügen nun den folgenden Quellcode in den Methodenbereich der MainActivity.java Klasse direkt nach der initializeContextualActionBar() Methode ein:

MainActivity.java

private AlertDialog createEditShoppingMemoDialog(final ShoppingMemo shoppingMemo) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    LayoutInflater inflater = getLayoutInflater();

    View dialogsView = inflater.inflate(R.layout.dialog_edit_shopping_memo, null);

    final EditText editTextNewQuantity = (EditText) dialogsView.findViewById(R.id.editText_new_quantity);
    editTextNewQuantity.setText(String.valueOf(shoppingMemo.getQuantity()));

    final EditText editTextNewProduct = (EditText) dialogsView.findViewById(R.id.editText_new_product);
    editTextNewProduct.setText(shoppingMemo.getProduct());

    builder.setView(dialogsView)
            .setTitle(R.string.dialog_title)
            .setPositiveButton(R.string.dialog_button_positive, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int id) {
                    String quantityString = editTextNewQuantity.getText().toString();
                    String product = editTextNewProduct.getText().toString();

                    if ((TextUtils.isEmpty(quantityString)) || (TextUtils.isEmpty(product))) {
                        Log.d(LOG_TAG, "Ein Eintrag enthielt keinen Text. Daher Abbruch der Änderung.");
                        return;
                    }

                    int quantity = Integer.parseInt(quantityString);

                    // An dieser Stelle schreiben wir die geänderten Daten in die SQLite Datenbank
                    ShoppingMemo updatedShoppingMemo = dataSource.updateShoppingMemo(shoppingMemo.getId(), product, quantity);

                    Log.d(LOG_TAG, "Alter Eintrag - ID: " + shoppingMemo.getId() + " Inhalt: " + shoppingMemo.toString());
                    Log.d(LOG_TAG, "Neuer Eintrag - ID: " + updatedShoppingMemo.getId() + " Inhalt: " + updatedShoppingMemo.toString());

                    showAllListEntries();
                    dialog.dismiss();
                }
            })
            .setNegativeButton(R.string.dialog_button_negative, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
                }
            });

    return builder.create();
}

Das Grundgerüst der neuen Methode sollte uns schon bekannt sein, da wir die meisten Anweisungen bereits im Theorie-Teil dieser Lektion kennengelernt haben.

In Zeile 2 erstellen wir das AlertDialog.Builder-Objekt, mit dessen Hilfe wir unseren AlertDialog zusammenbauen. Anschließend fordern wir die LayoutInflater-Instanz an. Sie wird für das Erzeugen des Dialog-Views aus der XML-Layout Datei benötigt.

In Zeile 5 erzeugen wir aus der in dieser Lektion erstellten XML-Layout Datei ein View-Objekt. Dieses View-Objekt weisen wir in Zeile 13 unserem AlertDialog als dessen Inhalt zu. Es wird den mittleren Bereich des Dialogs einnehmen, also zwischen Titel und Buttons.

Doch bevor wir dies tun, suchen wir mit Hilfe des View-Objekts nach den EditText-Feldern unseres AlertDialogs und setzen deren Inhalte auf die Werte der angeklickten ShoppingMemo. Die entsprechenden Anweisungen sind in den Zeilen 7 bis 11 angegeben.

Wie bereits beschrieben, weisen wir in Zeile 13 das View-Objekt unserem AlertDialog zu. Dazu rufen wir die Methode setView() auf dem AlertDialog.Builder-Objekt auf. Anschließend legen wir einen Titel für unseren Dialog fest.

Jetzt folgt der etwas kompliziertere Teil unserer neuen Methode. In den Zeilen 15 bis 42 fügen wir dem AlertDialog zwei Buttons hinzu und registrieren für beide jeweils einen OnClickListener.

Klickt der Nutzer auf den positiven Button (Ändern), lesen wir zuerst die neuen Werte aus den EditText-Feldern aus und speichern diese dann in der SQLite Datenbank mit Hilfe der updatedShoppingMemo() Methode unserer Datenquelle.

Anschließend weisen wir unsere SQLite App mit showAllListEntries() an, den ListView zu aktualisieren und dadurch die geänderten Werte des angeklickten Listeneintrags zusammen mit den unveränderten Einträgen auf dem Display auszugeben. Mit der Anweisung in Zeile 35 lassen wir den AlertDialog wieder schließen.

plhq_teaser_hbox_gelb_fotolia_RA Studio_46292813

Unser großes
Android Online-Kurs
Gesamtpaket



Weitere Infos

Klickt der Benutzer auf den negativen Button (Abbrechen), wird die cancel() Methode aufgerufen und dadurch der Dialog geschlossen.

Nun haben wir alle erforderlichen Eigenschaften unseres AlertDialogs definiert und können ihn jetzt zusammenbauen lassen. Dies erfolgt mit der return-Anweisung in Zeile 44. Wir lassen das AlertDialog-Objekt von dem Builder erstellen und geben es als Rückgabewert an die aufrufende Methode zurück.

Das war auch schon alles. Jetzt können wir mit einem Aufruf der Methode createEditShoppingMemoDialog() einen AlertDialog erstellen lassen und über ihn Datensätze unserer SQLite Datenbank ändern.

Wir sind nun einen großen Schritt weiter gekommen, was jetzt noch fehlt ist eine Möglichkeit die neue Methode über die grafische Benutzeroberfläche ausführen zu lassen. Dies werden wir im letzten Arbeitsschritt realisieren, indem wir die Methode initializeContextualActionBar() erweitern.

6.3 Erweitern der initializeContextualActionBar() Methode

Als letzte Änderung an unserem Projekt-Quellcode werden wir die Methode initializeContextualActionBar() erweitern. In ihr initialisieren wir die Contextual Action Bar, indem wir ihren MultiChoiceModeListener implementieren. Bisher haben wir zwei seiner fünf Callback-Methode überschrieben. Nun werden wir auch seine restlichen drei Callbacks ausprogrammieren.

Um möglichst keine Tippfehler zu begehen, ersetzen wir nun die bisherige initializeContextualActionBar() Methode der MainActivity.java Klasse vollständig mit folgendem Quellcode:

MainActivity.java

private void initializeContextualActionBar() {
    final ListView shoppingMemosListView = (ListView) findViewById(R.id.listview_shopping_memos);
    shoppingMemosListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);

    shoppingMemosListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {

        int selCount = 0;

        // In dieser Callback-Methode zählen wir die ausgewählen Listeneinträge mit
        // und fordern ein Aktualisieren der Contextual Action Bar mit invalidate() an
        @Override
        public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
            if (checked) {
                selCount++;
            } else {
                selCount--;
            }
            String cabTitle = selCount + " " + getString(R.string.cab_checked_string);
            mode.setTitle(cabTitle);
            mode.invalidate();
        }

        // In dieser Callback-Methode legen wir die CAB-Menüeinträge an
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            getMenuInflater().inflate(R.menu.menu_contextual_action_bar, menu);
            return true;
        }

        // In dieser Callback-Methode reagieren wir auf den invalidate() Aufruf
        // Wir lassen das Edit-Symbol verschwinden, wenn mehr als 1 Eintrag ausgewählt ist
        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            MenuItem item = menu.findItem(R.id.cab_change);
            if (selCount == 1) {
                item.setVisible(true);
            } else {
                item.setVisible(false);
            }

            return true;
        }

        // In dieser Callback-Methode reagieren wir auf Action Item-Klicks
        // Je nachdem ob das Löschen- oder Ändern-Symbol angeklickt wurde
        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            boolean returnValue = true;
            SparseBooleanArray touchedShoppingMemosPositions = shoppingMemosListView.getCheckedItemPositions();

            switch (item.getItemId()) {
                case R.id.cab_delete:
                    for (int i = 0; i < touchedShoppingMemosPositions.size(); i++) {
                        boolean isChecked = touchedShoppingMemosPositions.valueAt(i);
                        if (isChecked) {
                            int postitionInListView = touchedShoppingMemosPositions.keyAt(i);
                            ShoppingMemo shoppingMemo = (ShoppingMemo) shoppingMemosListView.getItemAtPosition(postitionInListView);
                            Log.d(LOG_TAG, "Position im ListView: " + postitionInListView + " Inhalt: " + shoppingMemo.toString());
                            dataSource.deleteShoppingMemo(shoppingMemo);
                        }
                    }
                    showAllListEntries();
                    mode.finish();
                    break;

                case R.id.cab_change:
                    Log.d(LOG_TAG, "Eintrag ändern");
                    for (int i = 0; i < touchedShoppingMemosPositions.size(); i++) {
                        boolean isChecked = touchedShoppingMemosPositions.valueAt(i);
                        if (isChecked) {
                            int postitionInListView = touchedShoppingMemosPositions.keyAt(i);
                            ShoppingMemo shoppingMemo = (ShoppingMemo) shoppingMemosListView.getItemAtPosition(postitionInListView);
                            Log.d(LOG_TAG, "Position im ListView: " + postitionInListView + " Inhalt: " + shoppingMemo.toString());

                            AlertDialog editShoppingMemoDialog = createEditShoppingMemoDialog(shoppingMemo);
                            editShoppingMemoDialog.show();
                        }
                    }

                    mode.finish();
                    break;

                default:
                    returnValue = false;
                    break;
            }
            return returnValue;
        }

        // In dieser Callback-Methode reagieren wir auf das Schließen der CAB
        // Wir setzen den Zähler auf 0 zurück
        @Override
        public void onDestroyActionMode(ActionMode mode) {
            selCount = 0;
        }
    });

}

In dem oberen Quellcode wurde über jede der fünf Callback-Methoden eine kurze Erläuterung eingefügt, Dadurch kann leichter nachvollzogen werden, was die Aufgabe des jeweiligen Callbacks ist.

Das sind die fünf Callback-Methoden des Listeners:

  • onItemCheckedStateChanged() – Wird aufgerufen, wenn ein Eintrag ausgewählt oder abgewählt wird. Hier zählen wir die Anzahl der ausgewählten Listeneinträge mit.
  • onCreateActionMode() – Wird bei Erzeugen der Contextual Action Bar aufgerufen. Hier legen wir die Menüeinträge (Action Items) an.
  • onPrepareActionMode() – Wird aufgerufen, wenn die Contextual Action Bar erzeugt wurde und manuell über die invalidate() Methode. Hier blenden wir das Ändern-Symbol aus, wenn mehr als ein Listeneintrag ausgewählt wurde.
  • onActionItemClicked() – Wird aufgerufen, wenn ein Action Item, also ein Menüeintrag der Contextual Action Bar angeklickt wurde. Hier reagieren wir auf Klicks auf das Löschen- und Ändern-Symbol.
  • onDestroyActionMode() – Wird aufgerufen, wenn der Action Mode beendet und somit auch die Contextual Action Bar geschlossen wird. Hier setzen wir den Zähler wieder auf 0 zurück.

Der Quellcode ist größtenteils selbsterklärend. Nur die onActionItemClicked() Callback-Methode ist etwas komplexer. Den ersten Teil haben wir bereits in der vorherigen Lektion des Android SQLite Tutorials kennengelernt. Neu ist der mittlere Teil in der Switch-Anweisung in den Zeilen 66 bis 81.

Darin lesen wir das zugehörige ShoppingMemo-Objekt aus dem angeklickten Listeneintrag aus. Anschließend lassen wir mit der Methode createEditShoppingMemoDialog() den AlertDialog erstellen und diesen mit der Methode show() anzeigen. Mit dem so erzeugten AlertDialog kann der entsprechende Datensatz unserer SQLite Datenbank geändert werden.

Weitere Infos über die Callback-Methoden des Action Modes könnt ihr hier finden:

6.4 Der komplette Quellcode der MainActivity-Klasse

Nun haben wir alle Änderungen an der MainActivity-Klasse vorgenommen. Mit dem eingefügtem Quellcode reagieren wir auf lange Klicks des Benutzers und löschen bzw. ändern die ausgewählten Listeneinträge zusammen mit den zugehörigen Datensätzen aus der SQLite Datenbank.

In dem unten angegebenen Quellcode ist die gesamte MainActivity-Klasse zur Kontrolle für euch aufgeführt. Die neu eingefügten Zeilen sind markiert worden.

In Android Studio sollte die MainActivity.java Klassendatei nun wie folgt aussehen:

An dieser Stelle endet der freie Inhalt dieser Lektion. Wir hoffen, sie hat dir bis hierher gefallen! Du kannst sie im geschützten Bereich von ProgrammierenLernenHQ fortsetzen, in welchem sich alle Lektionen unserer Android Online-Kurse befinden.

Unsere Android Kurse bestehen aus insgesamt 43 großen Lektionen und sind unterteilt in 13 frei zugängliche und 30 Premium-Lektionen. Die Premium-Lektionen befinden sich in dem geschützten Bereich und sind nur für Käufer unseres Android Online-Kurs Gesamtpaket zugänglich.

plhq_teaser_hbox_gelb_fotolia_RA Studio_46292813 An dieser Stelle endet der freie Inhalt dieser Lektion. Wir hoffen, sie hat dir bis hierher gefallen! Du kannst sie durch Kauf unseres Android Online-Kurs Gesamtpakets freischalten.

In unserem Android Online-Kurs Gesamtpaket befinden sich 43 große Lektionen, in denen wir dir schrittweise zeigen, wie voll funktionstüchtige Android Apps programmiert werden.

Diese Lektion ist Teil unseres Android Gesamtpakets. Insgesamt sind unsere Online-Kurse unterteilt in 13 frei zugängliche und 30 Premium-Lektionen.

Die Premium-Lektionen befinden sich in dem geschützten Bereich und sind nur für Käufer des Android Online-Kurs Gesamtpakets zugänglich.



Welche Inhalte befinden sich im Android Online-Kurs Gesamtpaket?

  • Das Gesamtpaket enthält alle Android Online-Kurse von ProgrammierenLernenHQ.
  • Im Paket enthalten ist unser großer Android Apps Programmieren Online-Kurs. Er ist unser Hauptkurs und besteht aus 35 großen Lektionen. Die Grundlagen der Android App Entwicklung praxisnah und verständlich zu lehren, ist das Hauptziel des Android Apps Programmieren Kurses.
  • Im Paket enthalten ist auch unser SQLite Datenbank App Programmieren Online-Kurs. Dieser Spezialkurs besteht aus 8 großen Lektionen und ist als weiterführender Kurs konzipiert worden. Der Kurs schließt an unseren Android Apps Programmieren Hauptkurs an und widmet sich dem speziellen Thema der SQLite Datenbanken.
  • Durch den Kauf erhältst du unbegrenzten Zugang zu allen Inhalten unseres Android Online-Kurs Gesamtpakets. Wir werden in Zukunft weitere Lektionen hinzufügen. Auch auf alle zukünftigen Lektionen erhältst du vollen Zugriff.

Wir hoffen, Dich bald als neuen Kursteilnehmer unserer Android Online-Kurse begrüßen zu dürfen!

Einmal kaufen und dadurch zeitlich unbegrenzten Zugriff auf alle Inhalte unseres Android Online-Kurs Gesamtpakets erhalten.



Hinweis: Der untere Quellcode ist Teil des geschützten Bereichs von ProgrammierenLernenHQ. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte.
Erfahre mehr über unsere Android Online-Kurse.

android_sqlite_lektion7_blurry

Der obere Quellcode ist Teil des geschützten Bereichs von ProgrammierenLernenHQ. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte.
Erfahre mehr über unsere Android Online-Kurse.

In der oberen Abbildung ist die MainActivity.java Klassendatei dargestellt. Es sind nur die Methoden initializeContextualActionBar() und createEditShoppingMemoDialog() aufgeklappt. Alle anderen Methoden sind unverändert geblieben und daher zugeklappt. Die hinzugefügten Codezeilen sind zudem mit Markierungen versehen worden.

Welche Bedeutung der jeweilige Code-Block besitzt, ist in der unteren Liste angegeben:

  1. A – Die benötigten Import-Anweisungen zum Sichtbarmachen der Klassen bzw. Interfaces DialogInterface, AlertDialog und LayoutInflater.
  2. B – Die initializeContextualActionBar() Methode wurde überarbeitet. Wir haben nun alle fünf Callback-Methode des MultiChoiceModeListener ausprogrammiert und der Contextual Action Bar einen weiteren Action Item, die Ändern-Aktion, hinzugefügt.
  3. C – Die Methode createEditShoppingMemoDialog(), durch die wir einen AlertDialog erzeugen lassen. Mit Hilfe dieses Dialogs können die Benutzer Änderungen an den Datenbankeinträge vornehmen.

Mit diesen Änderungen im Quellcode der MainActivity-Klasse haben wir unserer SQLite App eine weitere nützliche Funktion hinzugefügt. Wir können jetzt Datensätze aus der SQLite Datenbank unter Zuhilfenahme eines AlertDialogs ändern.

Im nächsten Abschnitt werden wird die erweiterte Contextual Action Bar unserer SQLite App testen und Einträge der Einkaufsliste und somit auch der hinterlegten SQLite Datenbank ändern.

7. Starten und Testen unserer SQLite App

Wir werden nun unserer Android App auf einem Android Virtual Device im Emulator ausführen lassen und überprüfen, ob Einträge über die Contextual Action Bar aus der SQLite Datenbank geändert werden können.

Hinweis: Wenn ihr Probleme beim Ausführen der App im Android Emulator oder auf einem Android Gerät haben solltet, könnt ihr unseren großen Android Apps Programmieren Kurs als Hilfe nutzen. Darin zeigen wir, wie eine Android App im Emulator oder auf einem physikalischen Android Gerät ausgeführt wird.

Unsere App starten wir dazu wie gewohnt über den Run > Run 'app' Menüeintrag, den wir über die obere Menüleiste erreichen.

Unsere SQLite App sollte jetzt auf dem Android Gerät gestartet worden sein. Die grafische Benutzeroberfläche der Anwendung hat sich auch diesmal nicht geändert, daher sieht auf dem Gerät alles genau so aus wie in der vorherigen Lektion.

Hinweis: Das Emulator-Fenster mit dem darin laufenden Android Virtual Device muss für die nächsten Arbeitsschritte geöffnet bleiben. Zudem muss in dem AVD unsere eigene App ausgeführt werden. Sollte dies nicht der Fall sein, muss die App erneut im Emulator gestartet werden.

Um die Log-Meldungen zu überprüfen, öffnen wir in Android Studio das Logcat Tool Window während unsere App auf dem AVD im Emulator ausgeführt wird.

Dazu führen wir die folgenden Schritte aus:

  1. Wir öffnen das Logcat Tool Window mit einem Klick auf den Logcat-Tab am unteren Bildschirmrand.
  2. Anschließend wählen wir Emulator Nexus_9 als AVD in der Drop-Down Liste aus.
  3. Nun wählen wir unsere App de.codeyourapp.shoppinglist in der Liste rechts daneben aus.
  4. Danach stellen wir die Prioritätsstufe auf Verbose ein.
  5. Und geben in das anschließende Suchfeld MainActivity|ShoppingMemo als Suchbegriff ein.
  6. Dann wählen wir den Eintrag Show only selected application in Liste ganz rechts aus.
android_sqlite_update_logcat_start

Überprüfen der Log-Meldungen unserer App im Logcat Tool Window von Android Studio

Nun klicken wir lange auf den zweiten Listeneintrag 3 x Saft, wodurch die Contextual Action Bar über die normale Action Bar gelegt wird.

In der Contextual Action Bar befinden sich nun zwei Symbole, ein Stift und ein Mülleimer. Außerdem erhalten wir Rückmeldung darüber wie viele Einträge gerade ausgewählt worden sind.

Mit einem Klick auf das Ändern-Symbol, den Stift, öffnet sich der AlertDialog und wir können den den ausgewählten Datensatz unserer SQLite Datenbank ändern. Wir erhöhen die Anzahl von 3 auf 4 und ändern Saft in Säfte um.

Anschließend bestätigen wir die Änderung des Listeneintrags mit dem Ändern Button unseres AlertDialogs:

android_sqlite_update_demo

Einträge aus der SQLite Datenbank mit Hilfe der Contextual Action Bar ändern

Jetzt haben wir den vorher ausgewählten Listeneintrag geändert, was wir auch direkt im ListView angezeigt bekommen. Als Nächstes schließen wir die SQLite App mit einem Klick auf den Back Button.

In der unteren Abbildung sind die Log-Meldungen nach dem Ändern des Listeneintrags (Markierung A) und anschließendem Beenden unserer Android App dargestellt:

android_sqlite_update_logcat_end

Es wurde ein Eintrag aus dem ListView und somit auch aus der Datenbank überarbeitet

Uns werden die folgenden Log-Meldungen ausgegeben:

01: MainActivity﹕ Das Datenquellen-Objekt wird angelegt.
02: ShoppingMemoDataSource﹕ Unsere DataSource erzeugt jetzt den dbHelper.
03: ShoppingMemoDbHelper﹕ DbHelper hat die Datenbank: shopping_list.db erzeugt.
04: MainActivity﹕ Die Datenquelle wird geöffnet.
05: ShoppingMemoDataSource﹕ Eine Referenz auf die Datenbank wird jetzt angefragt.
06: ShoppingMemoDataSource﹕ Datenbank-Referenz erhalten. Pfad zur Datenbank: /data/user/0/de.codeyourapp.shoppinglist/databases/shopping_list.db
07: MainActivity﹕ Folgende Einträge sind in der Datenbank vorhanden:
08: ShoppingMemoDataSource﹕ ID: 1, Inhalt: 5 x Äpfel
09: ShoppingMemoDataSource﹕ ID: 2, Inhalt: 3 x Saft
10: ShoppingMemoDataSource﹕ ID: 5, Inhalt: 3 x Kartoffeln
11: MainActivity﹕ Eintrag ändern
12: MainActivity﹕ Position im ListView: 1 Inhalt: 3 x Saft
14: MainActivity﹕ Alter Eintrag – ID: 2 Inhalt: 3 x Saft
15: MainActivity﹕ Neuer Eintrag – ID: 2 Inhalt: 4 x Säfte
16: ShoppingMemoDataSource﹕ ID: 1, Inhalt: 5 x Äpfel
17: ShoppingMemoDataSource﹕ ID: 2, Inhalt: 4 x Säfte
18: ShoppingMemoDataSource﹕ ID: 5, Inhalt: 3 x Kartoffeln
19: MainActivity﹕ Die Datenquelle wird geschlossen.
20: ShoppingMemoDataSource﹕ Datenbank mit Hilfe des DbHelpers geschlossen.

Die meisten Log-Meldungen sind bereits bekannt. Neu sind die Meldungen 11 bis 18, die über den geänderten Datenbankeintrag informieren und den aktuellen Inhalt der SQLite Datenbank ausgeben.

Ein Video veranschaulicht den Änderungsvorgang mit der Contextual Action Bar aber viel besser als ein Bild. Daher haben wir eine kleine Funktionspräsentation unserer SQLite App in Form eines Videos erstellt.

7.1 Video – Funktionspräsentation unserer SQLite App

In dem unteren Video haben wir einen Eintrag aus dem ListView und somit auch aus der SQLite Datenbank geändert. Im Video ist zu sehen, wie das Ändern mit Hilfe der Contextual Action Bar funktioniert. Außerdem wird gezeigt, wie das Ändern-Symbol ausgeblendet wird, wenn mehr als ein Listeneintrag ausgewählt ist.

Mit dieser neuen Funktion ist unsere Einkaufslisten-App jetzt schon ziemlich ausgereift. Unsere SQLite App ist zwar noch nicht vollständig, aber bereits vernünftig nutzbar.

In der nächsten Lektion unseres Android SQLite Datenbank Tutorials werden wir die App um eine wichtige Funktion erweitern, dem Abhaken von Einträgen. Aber für den Moment sind wir zufrieden mit dem Erreichten und können die selbst programmiere Android App für den nächsten Einkauf nutzen.

Zusammenfassung

In dieser Lektion des Android SQLite Tutorials haben wir neben dem SQL-Befehl update auch den AlertDialog von Android kennengelernt. Außerdem haben wir die Contextual Action Bar erweitert und dabei mehr über ihre Callback-Funktionen erfahren.

Zu Beginn dieser Lektion haben wir uns im Theorie-Teil mit dem Ändern von Datensätzen einer SQLite Datenbank beschäftigt. Dabei wurden auch die Callback-Methoden der Contextual Action Bar besprochen und die Klasse AlertDialog von Android vorgestellt.

Anschließend haben wir unser Android Projekt erweitert. Wir haben einen zweiten Menüeintrag der Contextual Action Bar hinzugefügt und ein Layout für den AlertDialog definiert. Danach haben wir in unserer Datenquelle eine neue Methode für das Ändern von Datensätzen der SQLite Datenbank definiert.

Die größten Änderungen haben wir an der MainActivity vorgenommen. In dieser Klasse haben wir eine neue Methode erstellt, mit der wir einen AlertDialog erstellen lassen, und die Callback-Methoden der Contextual Action Bar erweitert.

Abschließend haben wir unsere SQLite App auf dem Android Gerät ausgeführt und die Log-Meldungen analysiert. Zusätzlich haben wir den aktuellen Entwicklungsstand unserer Android App in einem Video festgehalten.

In dem nächsten Teil unseres Android SQLite Tutorials werden wir unsere Einkaufslisten-App um eine wichtige Funktion erweitern, dem Abhaken von Einträgen. Die Nutzer sollen mit einem kurzen Klick auf einen Eintrag des ListViews diesen abhaken können, dabei wird der zugehörige Text durchgestrichen werden.



Comments 9

  1. Hallo, super Anleitung!
    Bei mir werden jedoch

    deleteSelectedItems();
    updateSelectedItem();

    nicht erkannt (cannot resolve method).

    Bitte hilfe.

    1. Post
      Author

      Hallo Kingerst,

      danke für Dein Lob!

      In Abschnitt 1, mit den beiden Unterabschnitten 1.1 und 1.2, behandeln wir die Theorie, wie in Android Daten in der SQLite Datenbank mit Hilfe der Contextual Action Bar geändert werden können. Es handelt sich daher in Abschnitt 1 um Beispiel-Quellcode. Aus diesem Grund sind die beiden Methoden deleteSelectedItems() und updateSelectedItem() nicht ausprogrammiert, sondern nur beispielhaft angegeben.

      Ab Abschnitt 3 setzen wir die Theorie dann in die Praxis um und erweitern die ShoppingList-App um die besprochenen Funktionen. Dies funktioniert aber nur, wenn unser SQLite Kurs von der ersten Lektion an bis zu dieser Lektion hin absolviert wurde inkl. der geschützten Inhalte. Mehr über unsere Android Kurse kannst du hier erfahren.

      Viele Grüße,
      Chris

  2. Hallo Chris,
    perfektes Tutorial – sehr durchdacht.
    2 Fragen:
    1.) Wieso wird eigentlich die ID eines Datensatzes nicht im listview angezeigt, obwohl die ID ja Teil des ShoppingMemo´s ist.
    2.) Wenn ich auf die Checkbox zu einem Eintrag klicke passiert nichts – nur wenn ich lange darauf klicke wird die Checkbox angehakt und die CAB erscheint. Gibt es die Möglichkeit auch auf den Klick auf die Checkbox zu reagieren?

    Danke
    Gruß
    Eduardo

    1. Post
      Author

      Hallo Eduardo,

      danke für’s Lob!

      1) Weil die toString() Methode zum Darstellen des Datensatzes ausgeführt wird und von dieser die ID nicht ausgegeben wird.

      2) Mit einem Custom ListView, wie in unserem Android Kurs gezeigt, kann so etwas realisiert werden. Momentan werden die langen Klicks von der ContectualActionBar überwacht.

      Viele Grüße,
      Chris

    1. Post
      Author
  3. Hallo Chris

    vielen Dank für dein Tutorial. Es ist super. Sehr gut strukturiert. Man kann jedem Schritt exakt folgen, und weiß immer sofort, wo man etwas einfügen muss. Respekt.

    Eine kleine Frage hätte ich aber doch noch zur „Ändern“ Funktion.

    Kann es sein, dass Du der Einfachheit halber in der „onActionItemClicked“ Methode für cab_change einfach das .cab_delete im wesnetlichen kopiert hast?
    Ich meine den Bereich der Schleife. Denn eigentlich dürfte es hier ja nur genau 1 ! Element in „touchedShoppingMemoPositions geben, oder?

    Sobald mehr als 1 Element „touched“ ist, wird der Edit Button ja unsichtbar.
    Hätte man daher nicht einfach
    int postitionInListView = touchedShoppingMemosPositions.keyAt(0);
    nehmen können? ohne die Schleife drum herum?

    Gruß
    Carsten

    1. Post
      Author

      Hallo Carsten,

      danke für’s Lob!

      So genau weiß ich das jetzt auch nicht mehr. Es könnte so sein wie du es beschreibst. Wenn ich das Tutorial aktualisiere, werde ich mir das interne Verhalten der App einmal genauer im Debugger ansehen. Falls der Quellcode dann zu vereinfachen ist, werde ich ihn entsprechend verbessern. Vielen Dank für deinen Hinweis!

      Viele Grüße, Chris

  4. Pingback: Android SQLite Tutorial - Teil 1: SQLite Projekt anlegen

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.