Start Blog Arno Becker Gedächtnisstütze dank Android


2011.01.26 , 09:38:48

Gedächtnisstütze dank Android

Ein Buch hier, eine DVD da und dann noch 5 Euro für das Parkhaus. Wer öfters etwas verleiht stellt schnell fest, dass die Sachen nicht immer von alleine zurückgegeben werden. Ein einfaches Programm schafft Abhilfe und bietet gleichzeitig einen Einstieg in die Android-Programmierung.

So ärgerlich es ist, so wenig ist es meist eine böse Absicht des Anderen, etwas nicht zurückzugeben, was man sich geliehen hat. Ein einfaches Android-Programm schafft Abhilfe und demonstriert gleichzeitig einige zentrale Themen der Anwendungsentwicklung:

  • Oberflächen gestalten
  • Formulardaten auslesen
  • Menüs
  • Navigation
  • Datenspeicherung

Man gibt über ein Formular (LoanForm) ein, an wen man was verliehen hat und in welcher Menge. Die Eingabe speichert man mittels einer Schaltfläche, woraufhin man in die Übersichtsliste (LoanList) gelangt. Dort werden die verliehenen Gegenstände mit zusätzlicher Anzeige des Verleihdatums angezeigt.

In Abbildung 1 und 2 sieht man die beiden Bildschirmseiten.

Einstiegsbeispiel01-LoanForm

Abbildung 1 | Formular zum Eintragen verliehener Gegenstände.

Einstiegsbeispiel02-LoanList

Abbildung 2 | Anzeige der Verleihliste.

Ziel dieses Blogs ist, Android-Einsteigern anhand eines lauffähigen Programms wichtige Bausteine der Anwendungsentwicklung unter Android zu vermitteln.

Dabei wird auf alles verzichtet, was nicht unbedingt für das Funktionieren des Programms notwendig ist: Fehlerbehandlung, Optik, Bedienbarkeit etc.

Ein Android-Projekt aufsetzen

Wir beginnen mit dem Aufsetzen eines neuen Android-Projekts, das wir Verleihnix nennen. Abbildung 1 zeigt die notwendigen Einstellungen. Das Projekt wird in Eclipse mit dem ADT-Plugin (Android Development Tools) implementiert.

Einstiegsbeispiel03-New_Android_Project

Abbildung 3 | Verleihnix als Android-Projekt anlegen.

Wir starten mit der Eingabemaske und benennen die automatisch generierte Activity src/de.visionera.loan.MainActivity.java in LoanForm.java um. Die Namensänderung müssen wir auch im Android Manifest bekannt machen. Dazu ist der Activity-Tag wie folgt abzuändern:

<activity android:name=".LoanForm">

Wir nutzen die Gelegenheit und sorgen dafür, dass alle Bildschirmseiten der Anwendung mit einem weißen Bildschirmhintergrund angezeigt werden. Für solche Zwecke gibt es sogenannte Themes. Ein Theme definiert bestimmte Eigenschaften bezüglich Aussehen und Format einer Bildschirmseite. Themes können einzelnen Activities oder der gesamten Anwendung zugeordnet werden. Sie schaffen an zentraler Stelle eine Definition für ein einheitliches Aussehen. Es gibt auch einige vorgefertigte Themes im Android-SDK, von denen wir eines verwenden wollen. Dazu erweitern wir den Application-Tag im Android Manifest:

<application android:icon="@drawable/icon"
 android:label="@string/app_name" 
 android:theme="@android:style/Theme.Light">
</application>

Oberflächen gestalten

Die Activity LoanForm enthält später mehrere Oberflächenelemente zur Eingabe der Verleihdaten. Oberflächenelemente werden in Android als Views bezeichnet. Definiert werden Oberflächen die darauf angezeigten Views in XML-Dateien. Diese Dateien nennt man Layout.

Als Einsteiger muss man sich daran gewöhnen, dass bei der Erstellung von Oberflächen viel in XML definiert wird. Listing 1 zeigt das fertige Layout der Activity LoanForm. Wir müssen dazu die Datei /res/layout/main.xml abändern.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=
    "http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" >
 
  <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:padding="10sp"
    android:text="@string/tx_what" />
 
  <Spinner android:id="@+id/sp_what"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:drawSelectorOnTop="true" 
     android:entries="@array/sp_what_entries" />
 
  <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:padding="10sp"
    android:text="@string/tx_whom" />   
 
  <EditText android:id="@+id/edt_whom"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" />
 
  <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:padding="10sp"
    android:text="@string/tx_amount" />   
 
  <EditText android:id="@+id/edt_amount"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="0.0"
    android:inputType="numberDecimal" />
 
  <Button android:id="@+id/sf_save" 
    android:text="@string/tx_save"
    android:onClick="onSaveLoan" />
 
</LinearLayout>

Das Layout beschreibt die in Abbildung 1 gezeigte Oberfläche. Der äußere XML-Tag besagt, dass ein LinearLayout verwendet werden soll. Ein LinearLayout ist eine Anordnungsvorschrift für die Views. Es ordnet alle Views nacheinander an. Mittels des Attributs android:orientation="vertical" legt man fest, dass die Anordnung untereinander erfolgen soll. Für eine Anordnung nebeneinander sorgt der Wert horizontal.

Mehrfach findet man die Attribute android:layout_width und android:layout_height. Es stehen zwei Werte zur Verfügung. fill_parent bedeutet, dass das Layout oder die View so viel Platz einnehmen soll, wie im zur Verfügung steht. Oft ist dies die ganze Breite (width) oder Höhe (height) des Bildschirms. Der zweite mögliche Wert, wrap_content, bedeutet, dass das Oberflächenelement nur soviel Platz auf dem Bildschirm einnehmen soll, wie es braucht, um sich darzustellen.

android:layout_width="fill_parent", bewirkt in Listing 1 beispielsweise, dass die Oberflächenelemente in der Breite den gesamten Bildschirm einnehmen, also gestreckt werden.

Der XML-Tag TextView definiert ein statisches Textfeld. Ein Spinner ist eine Drop-Down-Liste mit Werten, die zur Auswahl stehen. Bei EditText handelt es sich um ein Texteingabefeld und bei Button um eine Schaltfläche.

Ressourcen definieren

Den Views und dem Layout wurden jeweils XML-Attribute zugefügt. Der Spinner besitzt beispielsweise das Attribut android:id="@+id/sp_what“. Über die XML-Attribute lässt sich auch das Aussehen der View verändern (z.B. Größe, Farbe, Abstände), worauf wir hier aus Platzgründen verzichtet haben ([1] Kap. 5).

„@+id“ bedeutet, dass automatisch eine eindeutige id generiert wird. Die View ist hierdurch aus dem Java-Quellcode über den Namen sp_what eindeutig referenzierbar. Dies ist wichtig, um später zu ermitteln, was der Anwender über den Spinner für eine Auswahl getroffen hat.

Den Namen (sp_what) kann man selbst definieren. Wir haben als Präfix „sp_“ verwendet, um deutlich zu machen, dass es sich um einen Spinner handelt.

Der Spinner erhält seine Werte aus einer sogenannten Ressourcendatei. In Android wird vieles als Ressource abgelegt, um Oberflächendefinitionen und Programmcode von darstellbaren Inhalten zu trennen.

Im Spinner findet man das Attribut android:entries="@array/sp_what_entries". Das @ zeigt an, dass es sich um einen Verweis auf eine Ressource handelt. „@array“ bedeutet, dass die Werte in der Datei /res/values/arrays.xml zu finden sind.

In der TextView über dem Spinner findet man das Attribut android:text="@string/tx_what". Dieses besagt, dass der in der TextView anzuzeigende Wert in einer Datei namens /res/values/strings.xml dem Schlüssel tx_what zu finden ist.

Wir legen also zunächst die Datei /res/values/strings.xml neu an. In ihr definieren wir alle statischen Texte, die in der Anwendung angezeigt werden (siehe Listing 2).

<resources>    
    <string name="app_name">Verleihnix</string>    
 
    <string name="tx_what">Was?</string>    
    <string name="tx_whom">An wen?</string>      
    <string name="tx_amount">Wie viel?</string>   
    <string name="tx_save">Speichern</string>  
    <string name="tx_show_list">Verleihliste</string>
    <string name="no_entries">Derzeit nichts verliehen.</string>
</resources>

Die Textwerte des Spinners lagern wir in die Ressourcendatei /res/values/arrays.xml aus (siehe Listing 3).

<resources>
  <array name="sp_what_entries">
    <item>DVD</item>
    <item>Buch</item>
    <item>Geld</item>
    <item>Auto</item>        
  </array>    
</resources>

Ein Vorteil der Auslagerung statischer Texte in separate Ressourcendateien ist die leichte Realisierung von Mehrsprachigkeit für eine Anwendung. Man kopiert einfach den Ordner values und nennt die Kopie z.B. values-en und übersetzt sämtliche Texte, um eine englischsprachige Version der Anwendung zu erhalten. Das Postfix „en“ ist ein zweistelliges Länderkürzel gemäß ISO 639-1.

Schaltflächen

Zu diesem Zeitpunkt ist die Anwendung lauffähig, aber ohne Funktion. Wir haben ein Formular zur Eingabe der Verleihdaten. Die Schaltfläche (Oberflächenelement Button in Listing 1) soll dafür sorgen, dass die Formulardaten gespeichert werden.

Wir müssen also eine Möglichkeit haben zu reagieren, wenn der Anwender die Schaltfläche drückt. Dazu dient das letzte Attribut in der Definition der Schaltfläche:

android:onClick="onSaveLoan"

Bei dem Attributwert onSaveLoan handelt es sich um den Namen einer zu implementierenden Methode. Die Methode wird dann aufgerufen, wenn die Schaltfläche gedrückt wird. Der Name kann frei gewählt werden.

Wir implementieren die Methode in der Activity, die das Layout verwendet, welches die Schaltfläche definiert. In unserem Fall ist dies die Activity LoanForm. Dort fügen wir folgenden Methodenrumpf ein:

public void onSaveLoan(final View sfSaveLoan) {

Wichtig ist, dass die Methode einen Parameter vom Typ View übergeben bekommt, sonst erhält beim Druck auf die Schaltfläche einen Laufzeitfehler.

Formulardaten auslesen

Wir brauchen die Methode, um die Eingaben in den Formularfeldern auszulesen und zu speichern. Listing 4 zeigt die vollständige Methode onSaveLoan.

public void onSaveLoan(final View sfSaveLoan) {
    // Was wurde verliehen?
    final Spinner spinner = (Spinner) findViewById(R.id.sp_what);
    final int {FNAMEL}">pos = spinner.getSelectedItemPosition();
    final String[] whatEntries = getResources().getStringArray(R.{FNAMEL}">array.sp_what_entries);
    final String conferred = whatEntries[{FNAMEL}">pos];
 
    // An wen?
    final EditText txtWhom =  (EditText) findViewById(R.id.edt_whom);       
    final String toWhom = txtWhom.{FNAMEL}">getText().toString();
 
    // Wie viel?
    final EditText txtAmount = 
 (EditText) findViewById(R.id.edt_amount);
    final float amount =  Float.parseFloat(txtAmount.{FNAMEL}">getText().toString());
 
  final StringBuilder sb = new StringBuilder();
    sb.append(toWhom);
    sb.append(" schuldet mir seit ");
    sb.append(DateUtils.formatDateTime(this, {FNAMEL}">System.currentTimeMillis(),
        DateUtils.FORMAT_SHOW_DATE));
    sb.append(": ");
    sb.append(conferred);
    sb.append(", Menge: ");
    sb.append(amount);
    sb.append("\r");
 
    try {
        saveEntry(sb.toString());
        } catch (IOException e) { }
    } catch (IOException e) { }
}

Zuerst ermitteln wir, welcher Gegenstand verliehen wurde. Dazu brauchen wir Zugriff auf den Spinner. Um im Java-Quellcode auf eine View zuzugreifen, verwendet man die Methode findViewById. Damit wir auf die richtige View zugreifen, hatten wir bei der Definition des Spinners im Layout dafür gesorgt, dass er sich eine eindeutige Id unter dem Namen sp_what generiert.

Android ermöglicht den Zugriff auf Ressourcen über eine Klasse namens R.java. Diese Klassen liegt unterhalb des Projektordners gen. Sie besteht nur aus inneren Klassen mit Konstanten. Die Konstanten haben automatisch generierte Integer-Werte.

Indem man der Methode findViewById die richtige Konstante übergibt, weiß das Programm, welches View-Element gemeint ist. Oberflächenelemente werden über ihre Id referenziert, daher wird der Methode die Konstante R.id.sp_what übergeben.

Nun ermitteln wir die Position des ausgewählten Werts im Spinner. Da der Spinner Werte anzeigt, die wir in der Datei /res/values/arrays.xml definiert haben, laden wir dieses Array und holen uns den richtigen Wert anhand der ermittelten Position pos. Innerhalb einer Activity kann man über die Methode getResources auf Ressourcen zugreifen. Die Methode getStringArray in Verbindung mit der Referenz sp_what_entries liefert ein String-Array mit den in arrays.xml definierten Werten.

Der Rest der Methode verläuft nach dem gleichen Muster. Am Ende wird mittels der Klasse StringBuilder ein Text aus den Werten generiert. Diesen speichern wir mit Hilfe der noch zu implementierenden Methode saveEntry im Dateisystem.

Daten speichern

Es gibt drei grundlegende Arten bei der Android-Programmierung, um Daten persistent zu speichern: als Schlüssel-Wert-Paare mit Hilfe des Objekts android.content.SharedPreferences, im Dateisystem oder in einer Datenbank. Wir verwenden das Dateisystem.

Listing 5 zeigt die Implementierung der Methode saveEntry aus Listing 4.

private void saveEntry(final String entry) throws IOException {
    OutputStreamWriter osw = null;
    try {
        final FileOutputStream fos = openFileOutput("verleihnix.txt", MODE_PRIVATE | MODE_APPEND);
        osw = new OutputStreamWriter(fos);
        osw.write(entry);        
    } catch (FileNotFoundException e) { }        
    finally {
        osw.close();
    } 
}

Die Methode ist weitgehend Standard-Java [2]. Lediglich die Methode openFileOutput ist Teil der Android-API. Mit dem Aufruf von openFileOutput legt man den Dateinamen und die Schreib- und Leseberechtigungen für die Datei fest.

Speicherort für Anwendungsdateien ist der Ordner files im Anwendungsverzeichnis des Programms (/data/data/packagename.der.anwendung). Das Anwendungsverzeichnis befindet sich im Gerätespeicher und nicht auf der SD-Karte.

Das Flag MODE_PRIVATE schützt die Datei vor unerlaubten Zugriffen aus anderen Programmen heraus. Will man die Datei für andere Anwendungen lesbar bzw. beschreibbar machen, so muss man das Flag MODE_WORLD_READABLE, bzw. MODE_WORLD_WRITEABLE verwenden.

Wir übergeben hier zusätzlich das Flag MODE_APPEND. Damit bewirken wir, dass die Datei bei einem erneuten Schreibvorgang nicht zuerst geleert wird, sondern neue Daten ans Ende der Datei angehangen werden.

Optionsmenüs

Nun können wir verliehene Gegenstände erfassen und speichern. Was uns nun noch fehlt, ist eine Anzeige der verliehenen Gegenstände. Dazu werden wir später eine zweite Activity implementieren (siehe Abbildung 2). Erreichbar ist diese Activity über ein Optionsmenü. Optionsmenüs sind über den Menü-Knopf des Emulators, bzw. des Android-Geräts erreichbar.

Wir legen den Ordner /res/menu an und darin eine XML-Datei mit dem Namen hauptmenue.xml. In Dieser Datei definieren wir, wie der Menüeintrag heißen soll (Listing 6).

<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:id="@+id/opt_show_list" android:title="@string/tx_show_list">  
</item></menu>

Wir kommen mit einem Eintrag aus. Er erhält eine Id (opt_show_list): Bei einem Eintrag ist dies nicht nötig, aber falls einmal weitere Menüeinträge hinzu kommen, ermittelt man anhand der Id, welcher der Einträge gedrückt wurde.

Den Text für den Menüeintrag legen wir wieder in der Datei strings.xml ab.

Verwendet eine Activity ein Optionsmenü, so muss dieses beim Start der Activity geladen werden. Wir überschreiben dazu in Activity LoanForm die Methode onCreateOptionsMenu, die zu Activity gehört (siehe Listing 7).

    public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.mainmenu, menu);
    return super.onCreateOptionsMenu(menu);
}

Die Methode bekommt einen Parameter namens menu übergeben. Da die Activity derzeit noch keine Menüeinträge hat, repräsentiert dieser Parameter ein leeres Menü.

Die Activity-Methode getMenuInflater liefert ein Objekt MenuInflator. Die auf dem MenuInflator aufgerufene Methode inflate fügt dem noch leeren Menü den in der Datei hauptmenue.xml definierten Menüeintrag hinzu.

Beim Überschreiben von Methoden in Activities ist es wichtig, abschließend mittels super die Methode der Oberklasse aufzurufen. Ruft der Anwender den Menüpunkt auf, soll die Activity darauf reagieren. Dazu fügen wir die in Listing 8 gezeigte Methode hinzu.

@Override
    public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.opt_show_list:        
        final Intent intent = new Intent(this, LoanList.class);         
        startActivity(intent);      
        break;
 
        default:          
    }
    return super.onOptionsItemSelected(item);
}

Die Methode onOptionItemSelected bekommt den gewählten Menüpunkt in Form eines MenuItem-Objekts übergeben. Rufen wir darauf die Methode getItemId auf, erhalten wir die Id unseres Menüeintrags, den wir in hauptmenue.xml definiert haben.

Die Switch-Case-Anweisung ist nur im Falle mehrerer Menüeinträge sinnvoll und dient nur als Hilfestellung für eigene Erweiterungen.

Navigation mittels Intents

In der Case-Anweisung in Listing 8 sorgen wir für den Aufruf einer zweiten Activity, die die Liste mit den verliehenen Gegenständen anzeigt.

Die Verknüpfung zweier Activities erfolgt mittels Intents. Intents bilden den „Leim“ zwischen den Komponenten einer Anwendung.

Ganz allgemein kann man mit Hilfe von Intents Komponenten (Activities, Services etc.) der eigenen Anwendung, aber auch Komponenten anderer Anwendungen aufrufen. So lassen sich Activities anderer Anwendungen, z.B. der Kontakte-Anwendung, die auf einem Android-Gerät vorinstalliert ist, aufrufen und in der eigenen Anwendung nutzen. Mehr dazu findet man in [3].

Um die Navigation zwischen Bildschirmseiten innerhalb einer Anwendung zu realisieren, verwendet man sogenannte explizite Intents. Bei diesen gibt man den Klassennamen der Ziel-Activity beim Erzeugen des Intents an.

Hat man eine Instanz des Intents erzeugt, ruft man die Methode startActivity mit dem Intent als Parameter auf. Alternativ zur Methode startActivity steht die Methode startActivityForResult zur Verfügung. Hier hat man einen Callback-Mechanismus zur Verfügung, der der aufrufenden Activity mitteilt, wenn die aufgerufene Activity beendet wurde. In der aufrufenden Activity wird beim Callback die Methode onActivityResult aufgerufen, die man überschreiben muss [4].

Es ist auch möglich, in einem Intent Daten an die aufzurufende Activity zu übergeben. Die Klasse Intent stellt zahlreiche Methoden zu diesem Zweck zur Verfügung. Daten können entweder in Form von Werten oder per URI (Uniform Resource Identifier) übergeben werden.

Intents sind ein zentrales Konzept von Android. Man unterscheidet zwischen expliziten, impliziten und Broadcast Intents. Der Intent, den wir in Listing 8 verwenden, nennt man expliziten Intent, da wir explizit eine Activity angeben, die aufgerufen werden soll. Eine gute Einführung in das Konzept der Intents findet man in [1] und [5].

Darstellung von Listen

Unser Programmcode ist derzeit nicht lauffähig. Es fehlt die Activity LoanList, die durch den Intent aufgerufen werden soll.

Wie der Name schon andeutet, stellt die Activity die ausgeliehenen Gegenstände in einer Liste dar. Zum Anzeigen von Listen gibt es eine spezielle Activity, die ListActivity. Sie verwendet eine spezielle View zur Darstellung von Listen, die ListView.

Wir beginnen wieder mit dem Erstellen eines Layouts (siehe Listing 9). Wir nennen es loan_list.xml und legen es unter /res/layout ab.

Als Anordnungsvorschrift für die Oberflächenelemente verwenden wir das schon bekannte LinearLayout. Darin enthalten sind zwei Views. Zum einem die ListView und zum anderen eine TextView. Beide haben eine spezielle Id, einmal android:list und einmal android:empty.

Die ListActivity, die wir gleich implementieren werden, erwartet diese beiden Views mit diesen beiden Ids in ihrem Layout. Die Darstellung einer Liste mit einem oder mehr Einträgen erfolgt in der ListView. Ist die Liste leer, wird die TextView angezeigt, die sich ihren darzustellenden Text aus der String-Ressource no_entries in der Dateien strings.xml holt.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <ListView
    android:id="@+id/android:list"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
  />
  <TextView
    android:id="@+id/android:empty"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/no_entries"
  />
</LinearLayout>

Nun legen wir die Activity de.visionera.loan.LoanList an. Bevor wir an die Implementierung gehen, tragen wir die Activity im Android Manifest ein. Alle Komponenten einer Anwendung, außer Komponenten, die als innere Klassen implementiert werden, müssen im Android Manifest deklariert werden. Dazu fügen wir innerhalb des Application-Tags den folgenden Eintrag hinzu:

<activity android:name=".LoanList"></activity>

Adapter

Die Implementierung der Activity LoanList ist in Listing 10 dargestellt.

public class LoanList extends ListActivity {
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.loan_list);
        String[] listEntries = null;
        try {
            listEntries = loadEntries();
        } catch (IOException e) { }
        ArrayAdapter<string> adapter = new ArrayAdapter<string>(this, 
        android.R.layout.simple_list_item_1, listEntries);
        setListAdapter(adapter);
    }
 
    private String[] loadEntries() throws IOException {
        BufferedReader br = null;
        try {
            final FileInputStream fis = openFileInput("verleihnix.txt");
            br = new BufferedReader(new InputStreamReader(fis));
            String line;
            final ArrayList<string> entries = new ArrayList<string>();
 
            while ((line = br.readLine()) != null) {
                entries.add(line);
            }
            return (String[])entries.toArray(new String[entries.size()]);
        } catch (FileNotFoundException e) { 
        } finally {
            br.close();    
        }
        return null;
    }
}</string></string></string></string>

LoanList wird von ListActivity abgeleitet. Diese spezialisierte Variante einer Activity stellt einen internen Mechanismus zur Verfügung, um die von einer Datenquelle gelieferten Daten in einer ListView darzustellen. Dazu ist ein sogenannter Adapter notwendig, der das Bindeglied zwischen der Darstellung der Daten auf der Oberfläche und der Datenquelle herstellt.

Der Adapter überwachte die Datenquelle und aktualisiert die Oberfläche im Falle des Einfügens, Veränderns oder Löschens von Datensätzen.

Es gibt verschiedene Arten von Adaptern, je nachdem, welche Datenquelle zum Einsatz kommt. Die gebräuchlichsten sind:

  • ArrayAdapter
  • SimpleCursorAdapter
  • CursorAdapter

Wir verwenden einen ArrayAdapter. Die Liste mit den verliehenen Gegenständen wird in der Methode loadEntries geladen. Dort kommt das Gegenstück zur schon bekannten Methode openFileOutput zum Einsatz. Mit Hilfe dieser Methode wird die Verleihliste aus dem Gerätespeicher geladen.

Da es sich um einzelne Textzeilen handelt, können wir diese einzeln einlesen. Gespeichert werden sie in einer ArrayList. Abschließend erfolgt eine Konvertierung in ein String-Array, welches an die aufrufende Methode onCreate zurückgeben wird. Dort liegt uns nun die Verleihliste in der Variablen listEntries vor. Nun erzeugen wir eine Instanz eines ArrayAdapters.

Layouts für Listeneinträge

Neben der Activity selber (bzw. dem Kontext der Anwendung, da Activity von Context abgeleitet ist) wird dem Konstruktor ein Layout zur Darstellung von Listeneinträgen mitgegeben. Das Android-SDK stellt dieses Layout zur Verfügung. Man greift wieder über eine Ressourcenreferenz aus der Klasse R auf das Layout zu. simple_list_item_1 ist ein Layout zur Darstellung einzelner Textzeilen. Dieses Layout enthält nur eine einzige TextView.

Es gibt einige weitere Layouts, die für Listeneinträge verwendet werden können [6]. Die Erstellung eigener Layouts für Listeneinträge ist natürlich auch möglich. Wie gesagt, Layouts sind nur Anordnungsvorschriften für ein oder mehrere Oberflächenelemente (Views). Ein Layout mit seinen Views muss keine ganze Bildschirmseite füllen.

Der letzte Parameter des Konstruktors ist schließlich die Verleihliste in Form eines String-Arrays.

Es folgt der Aufruf der Methode setListAdapter. Diese Methode übergibt der ListActivity den Adapter. Die ListActivity fügt automatisch die Werte aus dem String-Array in die ListView des Layouts ein. Pro Textzeile in listEntries erzeugt der Adapter einen Eintrag in der ListView, formatiert mit dem Layout simple_list_item_1. Damit haben wir das Ziel dieses Artikels erreicht. Die Verleihliste wird wie in Abbildung 2 dargestellt angezeigt.

Kür

Derzeit erhalten wir nach dem Speichern eines verliehenen Gegenstandes keine Rückmeldung, ob das Speichern erfolgreich war. Einfache Abhilfe schafft die anschließende Anzeige der Verleihliste, wo der gespeicherte Eintrag angezeigt werden sollte. Dazu ruft man am Ende der Methode onSaveLoan einfach die Verleihliste auf:

final Intent intent = new Intent(this, LoanList.class);
startActivity(intent);

Fazit

Die in diesem Artikel vorgestellte Anwendung deckt einige Themen ab, die in vielen Android-Anwendungen zum Einsatz kommen: Oberflächengestaltung, Optionsmenüs, Schaltflächen, Navigation, Darstellung von Listen, Persistenz etc.

Wir haben die Themen zwar nicht vertieft und auf vieles verzichtet, was eine professionelle Anwendung ausmachen würde, aber die Anwendung bietet eine gute Ausgangsbasis für eigene Experimente.

Einsteiger bemängeln oft die Menge an XML-Code, den es im Bereich der Oberflächen zu erstellen gilt. Abhilfe kann ein Layout-Editor schaffen. Einsteiger können sich den App Inventor [7] anschauen, mit dem sich ganze Android Anwendungen, aber auch nur deren Oberflächen erstellen lassen.

Quellen

[1] „Android 2 – Grundlagen und Programmierung“ von Arno Becker und Marcus Pant. Mai 2010, dpunkt-Verlag, 411 Seiten
[2] Exampledepot.com: http://www.exampledepot.com/taxonomy/term/164
[3] Intents: http://developer.android.com/reference/android/content/Intent.html
[4] Sub-Activities: http://developer.android.com/reference/android/app/Activity.html#StartingActivities
[5] Intents: http://developer.android.com/guide/topics/intents/intents-filters.html
[6] Layouts des Android-SDKs: http://developer.android.com/reference/android/R.layout.html
[7] App Inventor: http://appinventor.googlelabs.com/about/


Tags:






Impressum - AGB - Kontakt - Sidemap