Android_Tutorial_Lektion18_fotolia_RA_Studio_46292813

Programmier Tutorial: Apps für Android entwickeln – Teil 18: Einen angepassten ArrayAdapter für den ListView erstellen

In dieser Lektion werden wir unseren eigenen ArrayAdapter implementieren. Wir benötigen einen solchen angepassten ArrayAdapter, um die Inhalte der angeschlossenen Datenquelle gezielt zu extrahieren und anschließend auf die zugehörigen View-Elemente der ListView-Zeilen zu übertragen.

Der zu entwickelnde ArrayAdapter wird zum einen auf unser Datenmodell und zum anderen auf die visuelle Struktur des Zeilenlayouts abgestimmt sein. Er stellt die Verbindung zwischen Daten und Benutzeroberfläche her, indem der unsere Datenquelle mit dem ListView verbindet.


In Bezug auf die drei vorherigen Lektionen ist diese Lektion als letzter von vier Arbeitsschritten zu sehen, die für die Verbindung von Daten und Layout notwendig sind.

Zu Beginn dieser Lektion werden wir erklären, wie ein ArrayAdapter funktioniert und warum es notwendig ist, einen angepassten ArrayAdapter zu entwickeln. Anschließend werden wir zwei weitere Bilddateien, Autorenbilder von Goethe und Schiller, unserem Android Studio Projekt hinzufügen.

Danach erstellen wir die Klasse QuoteArrayAdapter.java in Android Studio. Wir werden sie direkt von der ArrayAdapter-Klasse ableiten und in ihr die Logik zum Verbinden von Daten und Benutzeroberfläche implementieren. Unsere Datenquelle werden wir dann über den erstellten ArrayAdapter mit dem bereits integrierten ListView verbinden.

Der angepasste Adapter wird in der Lage sein, sämtliche Inhalte aus der Datenquelle zu extrahieren und diese den korrespondierenden View-Objekten des Zeilenlayouts zuzuweisen. Abschließend werden wir unsere Android App im Emulator auf einem Android Virtual Device ausführen und die Funktionsweise des angepassten ArrayAdapters überprüfen.

1. Wie funktioniert ein Adapter in Android

In Android werden Datensammlungen mit Hilfe von Adaptern an View-Elemente der grafischen Benutzeroberfläche gebunden. Die Adapter fungieren dann als Bindeglied zwischen Datenquelle und View-Element. Sehr bekannte Beispiele für Adapter sind der ArrayAdapter und der CursorAdapter, die beide von der Klasse BaseAdapter abgeleitet und bereits für die Android Platform implementiert sind.

Über einen ArrayAdapter werden listenförmige Datensammlungen, bspw. Arrays oder java.util.List-Sammlungen, mit einem AdapterView verbunden. Über einen CursorAdapter hingegen werden Datenbanken, bspw. eine SQLite-Datenbank, mit einem AdapterView verbunden.

1.1 Was ist eine AdapterView

Ein AdapterView ist ein View-Element, dessen Kind-Elemente (Child-Elements) von einem Adapter vorgegeben werden. Ein AdapterView wird über einen Adapter mit einer Datenquelle verbunden. Über den Adapter erhält der AdapterView Zugang zu den Elementen der Datenquelle.

Dabei ist der Adapter für das Erzeugen der Kind-Elemente des AdapterViews verantwortlich. Jedes Kind-Elemente besitzt eine visuelle Struktur, die aus mehreren View-Elementen bestehen kann. Die View-Elemente füllt der Adapter mit den Inhalten der zugrunde liegenden Datenquelle.

Eine sehr bekannte AdapterView-Implementation der Android Platform ist der ListView. Die Kind-Elemente eines ListViews sind dessen Zeilen, die er sich von einem mit ihm verbundenen Adapter in Form von View-Hierarchien erzeugen lässt.

Weitere sehr bekannte Beispiele für AdapterView-Implementationen der Android Platform sind:

  • Gallery
  • Spinner
  • GridView
  • StackView
  • ExpandableListView

Allen diese AdapterView-Implementationen werden ihre Kind-Elemente von Adaptern vorgegeben. Es ist also die Aufgabe des verbundenen Adapters die Kind-Elemente für den AdapterView zu erstellen. Auf welche Art er dies ausführt, ist dem Adapter selbst überlassen. Am Beispiel des ArrayAdapters werden wir dies nun genauer betrachten.

1.2 Die Funktionsweise eines ArrayAdapters in Android

Wie alle Adapter in Android ist auch der ArrayAdapter von der BaseAdapter-Klasse abgeleitet. Ein ArrayAdapter verwaltet eine mit ihm verbundene Datenquelle und verarbeitet deren Inhalte zu individuelle Einträgen, den Kind-Elementen, eines ihm zugewiesenen AdapterViews.

Für das Erzeugen jedes Kind-Elements, bspw. einer Zeile bei einem ListView, wird ein vordefiniertes Zeilenlayout als Vorlage verwendet. Der ArrayAdapter erzeugt auf Basis dieses Zeilenlayouts eine View-Hierarchie in seiner getView() Methode. Diese View-Hierarchie besteht oft aus mehreren View-Elementen. In Falle unserer App setzt sich die vom Adapter erzeugte View-Hierarchie aus einem ImageView– und zwei TextView-Elementen zusammen.

Die auf diese Weise erzeugten View-Elemente müssen nun noch von dem ArrayAdapter mit passenden Inhalten befüllt werden. Dazu nutzt der Adapter die toString() Methode der verbundenen Datenquelle. Für jedes in der Datenquelle enthaltene Objekt ruft er dessen toString() Methode auf und weist deren Rückgabewert einem View-Element der View-Hierarchie zu.

Welches View-Element des Zeilenlayouts diesen Rückgabewert als Inhalt zugewiesen bekommt, kann frei gewählt werden. Dies geschieht beim Instanziieren des ArrayAdapters mit Hilfe der Ressourcen-ID des View-Elements. Wird dies nicht getan, so wird der ArrayAdapter standardmäßig mit dem View-Element mit der ID android.R.id.text1 verknüpft.

Etwas anderes als den Rückgabewert der toString() Methode kann der ArrayAdapter nicht an das verknüpfte View-Element weitergeben. Er ist somit auf die Zuordnung der toString() Methode auf ein View-Element des Zeilenlayouts beschränkt.

Um die Kontrolle über die Datenzuordnung zu erhalten und um mehr als ein View-Element des Zeilenlayouts mit Inhalten füllen zu können, ist es erforderlich einen angepassten ArrayAdapter zu implementieren. Wie dies erfolgt, besprechen wir im nächsten Abschnitt.

1.3 Anpassungen an einem ArrayAdapters vornehmen

Das Implementieren eines eigenen, angepassten ArrayAdapters ist sehr einfach. Es muss dazu eine neue Java-Klasse angelegt werden, die von der ArrayAdapter-Klasse abgeleitet ist. In dieser neuen Klasse muss nur die getView() Methode mit einer eigenen Implementierung überschrieben werden.

In der getView() Methode findet die Datenzuordnung statt. Sie ist die Schaltzentrale des Adapters und für die folgenden Aufgaben zuständig:

  • Erzeugen der View-Hierarchie – Auf Grundlage des Zeilenlayouts wird eine Hierarchie von View-Elementen erstellt. In dieser Hierarchie können beliebig viele View-Elemente enthalten sein. Bei unserer App besteht die Hierarchie aus einem ImageView– und zwei TextView-Elementen, die in einem RelativeLayout angeordnet sind.

  • Extrahieren der Inhalte – Der getView() Methode wird über ihren position-Parameter mitgeteilt, welches Element aus der angeschlossenen Datenquelle ausgelesen werden soll. Aus diesem Datenelement werden die relevanten Inhalte extrahiert und weiterverarbeitet, falls dies erforderlich ist.

  • Zuordnen der Inhalte – Die extrahierten Inhalte werden anschließend den zugehörigen View-Elementen des Zeilenlayouts zugeordnet. Dazu werden die View-Elemente anhand ihrer Ressourcen-ID aus der View-Hierarchie ausgelesen und mit den jeweils passenden Inhalt gefüllt.

  • Übergeben der befüllten View-Hierarchie – Schließlich wird die mit Inhalten befüllte View-Hierarchie an den aufrufenden AdapterView zurückgegeben. Der AdapterView wird dieses View-Objekt als Kind-Element verwenden. Bei einem ListView wäre dies die nächste ListView-Zeile.

Das unteren Quellcode-Beispiel zeigt eine einfache Implementierung der getView() Methode:

public View getView(int position, View convertView, ViewGroup parent) {

    // Erzeugen der View-Hierarchie auf Grundlage des Zeilenlayouts 
    LayoutInflater inflater = LayoutInflater.from(mContext);
    View rowView = inflater.inflate(R.layout.list_row, parent, false);

    // Anfordern des zur Listenposition gehörenden Datenobjekts
    Quote currentQuote = mQuoteList.get(position);
    
    // Finden der einzelnen View-Objekte in der View-Hierarchie (Zeilenlayout)
    TextView tvQuoteText   = (TextView) rowView.findViewById(R.id.quote_text);
    TextView tvQuoteAuthor = (TextView) rowView.findViewById(R.id.quote_author);
    ImageView ivAuthorImage  = (ImageView) rowView.findViewById(R.id.author_image);

    // Füllen der View-Objekte mit den passenden Inhalten des Datenobjekts
    tvQuoteText.setText(currentQuote.getQuoteText());
    tvQuoteAuthor.setText(currentQuote.getQuoteAuthor());
    ivAuthorImage.setImageResource(R.drawable.unknown);

    // Rückgabe der befüllten View-Hierarchie an den aufrufenden AdapterView
    return rowView;
}

Der angepasste ArrayAdapter muss eine View-Hierarchie für jedes Kind-Element des zugewiesenen AdapterViews erstellen. Dies erfolgt indem der AdapterView, in unserem Fall eine ListView-Instanz, die getView() Methode des angepassten ArrayAdapters für jedes Datenelement der Datenquelle aufruft.

Immer wenn dies geschieht erzeugt der Adapter in seiner getView() Methode die View-Hierarchie auf Basis einer ihm zugewiesenen Layout Datei. In unserem Fall ist dies das Zeilenlayout für den ListView, welches in der list_row.xml Datei von uns definiert wurde.

In den Zeilen 4 und 5 wird mit Hilfe dieser XML-Layout Datei die View-Hierarchie für eine Zeile des ListViews erzeugt. Für das Erzeugen des View-Objekts wird der LayoutInflator, ein System Service von Android, genutzt.

In Zeile 8 wird das zu verwendende Datenobjekt aus der Datenquelle ausgelesen. Welches Objekt dies ist, wird von dem position-Parameter der getView() Methode vorgegeben.

Anschließend wird in den Zeilen 11 bis 13 nach den relevanten View-Elementen des Zeilenlayouts mit Hilfe ihrer Ressourcen-IDs gesucht. In unserem Fall sind das ein ImageView– und zwei TextView-Elemente. Diese drei View-Elementen werden dann in den Zeilen 16 bis 18 mit Inhalten des Datenobjekts befüllt.

Die nun mit den passenden Inhalten ausgestattete View-Hierarchie wird schließlich in Zeile 21 an den aufrufenden AdapterView, bei uns die ListView-Instanz, zurückgegeben. Dieser verwendet das erhaltene View-Objekt als Kind-Element, bspw. als eine ListView-Zeile.

Mit diesen wenigen Zeilen Code erhält man einen an die Bedürfnisse des eigenen Projekts angepassten ArrayAdapter. Weitere Anpassungen müssen an der ArrayAdapter-Klasse nicht vorgenommen werden.

Wir werden weiter unten in dieser Lektion, wenn wir unseren eigenen angepassten ArrayAdapter implementieren, die eben besprochene Theorie in die Praxis umsetzen. Doch zunächst müssen noch einige Vorbereitungen an unserem Android Projekt getroffen werden.

2. Einfügen weiterer Bilddateien in das Projekt

Wir werden nun zwei weitere Bilddateien als App Ressourcen unserem Android Studio Projekt hinzufügen. Die beiden Bilddateien werden wir in den drawable/ Ordner einfügen und später als Autorenbilder für Johann Wolfgang v. Goethe und Friedrich Schiller verwenden.

Bevor wird die beiden Bilddateien als App Ressource in unser Android Projekt einfügen können, müssen wir sie folgendermaßen herunterladen:

  1. Mit der linken Maustaste klicken wir jeweils auf die beiden folgenden Links: Goethe und Schiller.
  2. Es öffnet sich ein neuer Tab mit dem jeweiligen Autorenbild. Wir klicken mit der rechten Maustaste auf das Bild.
  3. In dem aufgehenden Kontext-Menü klicken wir auf den Bild speichern unter… Eintrag.
  4. Anschließend speichern wir die Bilder unter dem Dateinamen goethe.png bzw. schiller.png in einem beliebigen Ordner ab.

Die Bilddateien goethe.png und schiller.png sollten nun in einem Ordner auf eurem Rechner abgespeichert worden sein. Wir werden diese Dateien in den nächsten Schritten unserem Projekt hinzufügen. Dazu muss Android Studio geöffnet sein und in dem Project Tool Window muss die Project-Ansicht ausgewählt sein.

Wir werden nun den drawable-Ordner unseres Projekts im Explorer wie folgt öffnen:

  1. Wir klicken mit der rechten Maustaste auf den drawable/ Ordner unseres Projekts in Android Studio.
  2. Anschließend klicken wir im Kontext-Menü auf den Show in Explorer Eintrag.
arrayadapter_show_folder

Öffnen des drawable/ Ordners im Explorer

Es öffnet sich der res/ Ordner in einem neuen Explorer-Fenster. In diesem Ordner klicken wir doppelt auf den drawable/ Ordner, wodurch wir in diesen hinein navigieren:

listview_res_folder

In dem res/ Ordner unseres Projekts klicken wir doppelt auf den drawable/ Ordner

Wir kopieren nun die heruntergeladenen Dateien goethe.png und schiller.png in den drawable/ Ordner (Markierung A) hinein. Das Ergebnis sollte bei euch folgendermaßen aussehen:

project_drawable_folder

In dem drawable/ Ordner wurden die Bilddateien goethe.png und schiller.png hinein kopiert

Die beiden Bilddateien haben wir nun unserem Android Projekt als Drawable-Ressource hinzugefügt. Wir können ab jetzt per Quellcode oder von einer XML-Layout Datei aus auf diese App Ressourcen zugreifen.

In Android Studio sollte die eingefügten Bilddateien jetzt unter dem drawable/ Ordner aufgeführt werden:

drawable_resources_added_2a

Die Bilddateien goethe.png und schiller.png sind nun unter dem drawable/ Ordner aufgeführt

Mit dem Hinzufügen dieser beiden Drawable-Ressourcen sind nun die Vorbereitungen an unserem Android Projekt abgeschlossen. Wir können jetzt mit dem Erstellen des angepassten ArrayAdapters beginnen.

3. Erstellen des angepassten ArrayAdapters

Wir werden nun unseren angepassten ArrayAdapter implementieren. Dazu müssen wir eine neue Java Klasse angelegen und sie von der ArrayAdapter-Klasse ableiten. Die neue Klasse muss sich zudem in dem Package-Ordner unseres Android Projekts befinden.

Um die neue Klasse anzulegen, klappen wir die Project-Ansicht exakt so wie in Lektion 4 Abschnitt 2 beschrieben auf. In den Package-Ordner unseres Projekts werden wir nun die neu Klassendatei mit Hilfe des Create New Class-Dialogs von Android Studio anlegen lassen.

Die neue Klasse, mit dem Namen QuoteArrayAdapter, legen wir nun folgendermaßen an:

  1. Mit der rechten Maustaste auf den Package-Ordner de.codeyourapp.zitate klicken.
  2. Anschließend den Eintrag New des Kontext-Menüs anklicken.
  3. Danach auf den Eintrag Java Class klicken.
adapter_new_class

Erstellen der Klasse für den angepassten ArrayAdapter in den Package-Ordner des Projekts

Anschließend öffnet sich der Create New Class-Dialog, der uns bei der Erstellung der neuen Java Klasse unterstützt. Wir müssen nur einige Felder des Dialogs ausfüllen.

In dem Create New Class-Dialog nehmen wir nun die folgenden Einstellungen vor:

  1. Als Klassennamen tragen wir in das Feld Name QuoteArrayAdapter ein.
  2. Den Wert für Kind lassen wir auf Class stehen.
  3. Die Felder Superclass und Interface(s) lassen wir leer.
  4. Als Package sollte bereits automatisch unser Package-Ordner de.codeyourapp.zitate eingetragen sein.
  5. Alle anderen Einstellungen übernehmen wir unverändert.
  6. Den Dialog bestätigen wir mit einem Klick auf den OK Button.
adapter_klasse_benennen

Den Namen für die Klasse des angepassten ArrayAdapters vorgeben

Android Studio legt nun automatisch die neue Java Klasse an. Dabei wird auch der minimale Quellcode für das Klassengerüst erzeugt. Diesen benötigen wir aber nicht und werden ihn daher vollständig durch unseren eigenen Code ersetzen.

Dazu öffnen wir die Klassendatei QuoteArrayAdapter.java im Editorfenster von Android Studio mit einem Doppelklick auf den entsprechenden Eintrag in der linken Project-Ansicht.

Anschließend ersetzen wir den gesamten Quelltext mit folgendem Code:

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 unserer Android Online-Kurse 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 unserer Android Kurse. 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. Dieser besteht aus 35 großen Lektionen und ist als Einstiegskurs konzipiert worden. 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 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 all unseren Android Online-Kursen. Wir werden in Zukunft weitere Android Kurse hinzufügen. Auch auf alle zukünftigen Kurse 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 unserer Android Online-Kurse 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_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

Die QuoteArrayAdapter-Klasse ist von der ArrayAdapter-Klasse abgeleitet worden. Sie besitzt die folgenden sechs Instanzvariablen:

  • mContext – Hier speichern wir die Referenz auf das Context-Objekt ab. In unserem Fall ist dies die MainActivity-Instanz, durch die wir Zugriff auf die Anwendungsumgebung (Application Environment) erhalten. Wir werden diese Membervariable nutzen, um auf die App Ressourcen und System Services zugreifen zu können.

  • mQuoteList – Diese Membervariable hält eine Referenz auf die Zitate-Objekte unserer Android App. Sie ist die Datenquelle des angepassten ArrayAdapters und mit den darzustellenden Quote-Objekten gefüllt.

  • mLayoutInflater – Die LayoutInflater-Instanz nutzen wir für das Erzeugen der View-Hierarchie. Dazu erzeugt der LayoutInflater aus der XML-Layout Datei list_row.xml die korrespondierenden View-Objekte des Zeilenlayouts und fasst diese in einer View-Hierarchie zusammen.

  • mResources – In dieser Membervariablen halten wir eine Referenz auf die Resources-Instanz unserer Android App. Über die Resources-Instanz können wir auf die Ressourcen unserer Anwendung, bspw. auf die Autorenbilder oder Beispielzitate, zugreifen.

  • mPackageName – Hierin speichern wir den Package-Namen unserer Anwendung ab. Wir benötigen ihn, um die Ressourcen-IDs der Autorenbilder anzufragen.

  • mQuoteAuthorDrawables – In dieser Instanzvariable vom Typ Map speichern wir die Autorenbilder als Drawable-Objekte ab. Später werden wir unseren ListView die Autorenbilder aus dieser Map laden lassen, was zu einem deutlich flüssigeren Scrollen führen wird, da die Bilder bereits als Drawable-Objekte vorliegen.

Der Konstruktor der QuoteArrayAdapter-Klasse

In dem Konstruktor unserer Klasse QuoteArrayAdapter müssen wir zuerst den Konstruktor der Superklasse ArrayAdapter aufrufen. Diesem übergeben wir als Argumente das Context-Objekt, die Ressourcen-ID des Zeilenlayouts und die Liste mit den Quote-Objekten.

public QuoteArrayAdapter(Context context, List<Quote> quoteList) {
    super(context, R.layout.list_row, quoteList);

    mContext = context;
    mQuoteList = quoteList;
    mLayoutInflater = LayoutInflater.from(context);
    mResources = context.getResources();
    mPackageName = context.getPackageName();
    
    createQuoteAuthorDrawables();
}

Anschließen weisen wir den Membervariablen ihre Referenzen zu. In der Variable mQuoteList werden die darzustellenden Quote-Objekte in einer ArrayList gehalten. Sie ist die Datenquelle unseres angepassten ArrayAdapters, aus der die Inhalte für die Zeilen des ListViews vom Adapter extrahiert werden.

In Zeile 10 rufen wir die createQuoteAuthorDrawables() Methode auf, in der die Autorenbilder in Drawable-Objekte umgewandelt und in einer Map gespeichert werden.

Die createQuoteAuthorDrawables() Methode der QuoteArrayAdapter-Klasse

Die createQuoteAuthorDrawables() Methode wird nur einmal, direkt beim Erzeugen der QuoteArrayAdapter-Instanz aufgerufen. Sie ist für das Umwandeln der Autorenbilder in Drawable-Objekte und das Speichern dieser ein einer Map zuständig. Dies ist für die flüssige Bedienbarkeit unseres ListViews von großer Bedeutung, da er über die Map direkt auf die Drawable-Objekte zu greifen und der rechenintensive Umwandlungsprozess umgangen werden kann.

private void createQuoteAuthorDrawables() {
   int imageId;
   String[] quoteAuthors = mResources.getStringArray(R.array.quote_authors);

   for (String author : quoteAuthors)
   {
      imageId = mResources.getIdentifier(author, "drawable", mPackageName);
      if (imageId > 0) {
         mQuoteAuthorDrawables.put(author, ContextCompat.getDrawable(mContext, imageId));
      }
   }
}

Das Erzeugen der Drawable-Objekte wird folgendermaßen durchgeführt. In Zeile 3 fordern wir mit Hilfe der Resources-Membervariable mResources die Autoren-IDs an, über welche wir später auf die Autorenbilder zugreifen können. Die zurückerhaltenen Autoren-IDs werden in dem String-Array quoteAuthors abgespeichert.

Die Autoren-IDs sind als Array-Ressource in der arrays.xml Ressourcen-Datei von uns in einer früheren Lektion hinterlegt worden. Der Zugriff erfolgt dabei über die Ressourcen-Klasse R und den Namen des String-Arrays. Zu beachten ist, dass hierbei nicht auf die Datei arrays.xml zugegriffen wird, sondern auf die innere Klasse array der Ressourcen-Klasse R, welche automatisch beim Kompilieren unseres Projekts generiert wird.

In der for-Schleife von Zeile 5 bis 11 wird nun die Ressourcen-ID eines jeden Autorenbilds angefordert. Dies erfolgt über die getIdentifier() Methode, der als Argumente die Autoren-ID, ein String mit dem Wert drawable und der Package-Name unserer App übergeben werden.

Die getIdentifier() Methode liefert anschließend die zum jeweiligen Autorenbild gehörende Ressourcen-ID zurück. Dabei wird in den Ressourcen-Ordner drawable/ nach einem Bild mit dem Namen der übergebenen Autoren-ID (bspw. goethe oder schiller) gesucht. Die Dateiendung wird dabei nicht berücksichtigt. Existiert ein passendes Bild, wird dessen Ressourcen-ID, ein Int-Wert, zurückgegeben.

Anschließend wird in Zeile 9 mit Hilfe der angeforderten Ressourcen-ID ein Drawable-Objekt aus der zugehörigen Bild-Ressourcendatei erzeugt und in der Map-Instanzvariable mQuoteAuthorDrawables abgespeichert. Auf diese Weise werden alle Autorenbilder in Drawable-Objekt umgewandelt und in der Map unter dem Schlüssel der jeweiligen Autoren-ID abgelegt.

Die getView() Methode der QuoteArrayAdapter-Klasse

Jedes Mal wenn der ListView eines seiner Kind-Elemente (eine Zeile) darstellen muss, ruft er die getView() Methode des mit ihm verbundenen Adapters, des QuoteArrayAdapters, auf. Von der getView() Methode wird dann die View-Hierarchie für das Kind-Element, die Zeile, erstellt, mit Inhalten der Datenquelle befüllt und an den aufrufenden ListView zurückgegeben.

Im unteren Quelltext ist die getView() Methode des QuoteArrayAdapters aufgeführt:

android_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

In den Zeilen 4 bis 10 wird die View-Hierarchie der ListView-Zeile mit Hilfe des LayoutInflaters erzeugt. Dies muss aber nur in den Fällen erfolgen, in welchen keine bereits vorhanden View-Hierarchie wiederverwendet werden kann.

Ist eine wiederverwendbare View-Hierarchie vorhanden, so wird eine Referenz auf sie in der convertView Variable gespeichert. Diese nicht mehr benötigten View-Hierarchie, stellte einmal eine ListView-Zeile dar, die momentan nicht mehr auf dem Bildschirm zu sehen ist. Sie kann daher weiter genutzt und mit neuen Inhalten befüllt werden.

In Zeile 13 wird das zu der darzustellenden ListView-Zeile gehörende Datenobjekt aus der Datenquelle angefordert. Wir nutzen dazu die Variable position, in der die Zeilennummer der darzustellenden ListView-Zeile gespeichert ist. Das angeforderte Datenobjekt, ein Quote-Objekt, enthält alle Inhalte die wir zum Befüllen der View-Hierarchie benötigen.

In den Zeilen 16 bis 18 wird nach den relevanten View-Objekten in der View-Hierarchie gesucht. Dazu wird die findViewById() Methode auf der View-Hierarchie aufgerufen und ihr die Ressourcen-ID des gesuchten View-Objekts übergeben. Die zurückerhaltenen View-Objekte müssen nun noch mit Inhalten des Datenobjekts befüllt werden.

Dies geschieht in den Zeilen 21 bis 27. Über die get-Methoden der Quote-Klasse erhalten wir Zugriff auf die Inhalte des Datenobjekts. Den TextView-Objekten tvQuoteText und tvQuoteAuthor weisen wir mit der setText() Methode direkt den Zitattext bzw. den Namen des Autors aus der Datenquelle zu.

Für das ImageView-Objekt ivAuthorImage müssen wir einen kleinen Umweg gehen. In Zeile 24 fragen wir über die get() Methode das Drawable-Objekt des auszugebenden Autorenbilds bei der Map-Instanzvariablen an. Dabei übergeben wir der Methode die Autoren-ID als Schlüssel.

Das zurückerhaltene Drawable-Objekt wird schließlich in Zeile 26 dem ImageView als das darzustellende Autorenbild zugewiesen. Falls für die angefragte Autoren-ID kein Drawable-Objekt gefunden werden kann, wird kein Autorenbild zugewiesen und stattdessen das Standard-Autorenbild (unknown.png) verwendet.

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

android_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

Wir haben nun unseren eigenen angepassten ArrayAdapter implementiert. Unser QuoteArrayAdapter ist in der Lage den ListView unserer Android App mit passenden Inhalten aus der verbundenen Datenquelle zu versorgen. Dazu müssen wir ihn nur noch mit dem ListView zu verbinden.

4. Verbinden des angepassten ArrayAdapters mit dem ListView

Unser ListView ist bereits mit einem normalen ArrayAdapter verbunden. Die Zuweisung ist in der bindAdapterToListView() Methode der MainActivity-Klasse erfolgt. Wir werden nun in dieser Methode eine Instanz der QuoteArrayAdapter-Klasse erzeugen und diese dem ListView als neuen Adapter zuweisen.

Im unteren Quellcode sind die eben besprochenen Änderungen bereits durchgeführt und die nicht mehr benötigten Codezeilen auskommentiert worden:

android_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

Die Zeilen 3 bis 11 werden nicht mehr benötigt und sind daher auskommentiert worden. Sie waren für die Instanziierung und Zuweisung des normalen ArrayAdapters zuständig. Da wir den normalen ArrayAdapter nicht mehr verwenden werden, können die auskommentierten Zeilen gelöscht werden.

In Zeile 14 wird das QuoteArrayAdapter-Objekt instanziiert. Wir übergeben dem Konstruktor dazu eine Referenz auf das Activity-Objekt (this) und die Datenquelle (mQuoteList), welche die Quote-Objekte enthält.

In den Zeilen 15 und 16 suchen wir nach dem ListView-Objekt mit Hilfe der findViewById() Methode, der wir die Ressourcen-ID des ListView-Elements übergeben. Diesem ListView-Objekt weisen wir mit der setAdapter() Methode anschließend die QuoteArrayAdaper-Instanz, unseren angepassten ArrayAdapter, zu.

Um die eben beschriebenen Änderungen am Quellcode durchzuführen, öffnen wir die Klassendatei MainActivity.java im Editor von Android Studio. Dazu klicken wir doppelt auf ihren Dateinamen im Project Tool Window. Die Klassendatei befindet sich im Package-Ordner de.codeyourapp.zitate unseres Projekts.

Im unteren Quellcode der MainActivity.java Datei wurden die Änderungen bereits durchgeführt und sind grau markiert:

android_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

Im oberen Quellcode der MainActivity-Klasse wurden nur in der bindAdapterToListView() Methode Änderungen vorgenommen. Und zwar wurde der Inhalt des Methodenrumpfs ausgetauscht. Die neu eingefügten Anweisungen befinden sich in den Zeilen 48 bis 50. Der Methodenkopf ist unverändert geblieben.

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

android_programmieren_lernen_blurry_sourcecode

Der obere Quellcode ist Teil des geschützten Bereichs. Durch Freischalten unserer Android Online-Kurse erhältst du Zugriff auf alle geschützten Inhalte. Klicke auf die Info-Box, um mehr zu erfahren.

In der oberen Abbildung ist die überarbeitete MainActivity.java Klassendatei dargestellt. Der Quellcode wurde an genau einer Stelle (Markierung A) überarbeitet. Der neue Methodenrumpf ist bereits in die bindAdapterToListView() Methode eingefügt worden.

Wir haben somit den ListView über den QuoteArrayAdapter mit der Datenquelle verbunden. Wenn der ListView von nun an neue Zeilen anfragt, wird der mit ihm verbundene angepasste ArrayAdapter die dafür benötigten View-Elemente erstellen. Der Adapter wird die dazu erforderlichen Inhalte aus der mit Quote-Objekten gefüllten Datenquelle extrahieren und sie den drei korrespondierenden View-Elementen des Zeilenlayouts zuweisen.

Wie dies zur Laufzeit auf einem Android Gerät aussieht, werden wir im nächsten Abschnitt erfahren, wenn wir unsere Android App im Emulator auf einem Android Virtual Device ausführen und den angepassten ArrayAdapter im Normalbetrieb testen.

5. Ausführen und Testen unserer Android App

Wir werden nun unserer Android App auf einem Android Virtual Device im Emulator ausführen lassen. Auf diese Weise können wir das Aussehen und Verhalten des ListViews in Verbindung mit unserem angepassten ArrayAdapter direkt in unserer App betrachten.

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

Auf dem virtuellen Gerät sieht unsere Android App nun wie folgt aus:

screenshot_adapter

Die Zeilen des ListViews werden nun von unserem angepassten ArrayAdapter mit den passenden Inhalten versorgt

In der oberen Abbildung ist der Startbildschirm, die Start-Activity, unserer App dargestellt. Er besteht aus einem Button und dem ListView. Die Zeilen des ListViews werden nach den Vorgaben des Zeilenlayouts erstellt, welches wir in einer vorherigen Lektion definiert haben. Sie bestehen jeweils aus drei View-Elemente, ein ImageView und zwei TextViews.

Die vier bereits dargestellten ListView-Zeilen wurden nun von unserem angepassten ArrayAdapter, dem QuoteArrayAdapter, erstellt. Dazu hat er aus der verbundenen Datenquelle jeweils ein Quote-Objekt extrahiert und dessen Inhalte mit Hilfe der get-Methode ausgelesen. Die zurückerhaltenen Inhalte hat der QuoteArrayAdapter anschließend den korrespondierenden View-Objekten der jeweiligen ListView-Zeile zugewiesen.

Da wir nun unseren eigenen angepassten ArrayAdapter verwenden, werden alle View-Element des Zeilenlayouts mit extrahierten Inhalten gefüllt. Den beiden TextView-Elemente werden der Zitattext bzw. der Autorenname zugewiesen und dem ImageView-Element wird als Inhalt das dazu passende Autorenbild zugeteilt.

Zusammenfassung

In dieser Lektion haben wir einen angepassten ArrayAdapter für unseren ListView implementiert. Dazu haben wir die Java-Klassendatei QuoteArrayAdapter.java angelegt. Mit Hilfe dieser Klasse werden alle in der Datenquelle befindlichen Inhalte ausgelesen und an die korrespondierenden View-Elemente des Zeilenlayouts weitergegeben.

Weiterhin haben wir uns zu Beginn der Lektion ausgiebig mit der Funktionsweise von Adaptern in Android am Beispiel des ArrayAdapters beschäftigt. Anschließend haben wir zwei weitere Bilddateien als App Ressourcen unserem Android Studio Projekt hinzugefügt.

Nachdem wir den angepassten ArrayAdapter mit dem ListView unserer Anwendung verbunden hatten, haben wir unsere Android App im Emulator auf einem Android Virtual Device ausgeführt und die korrekte Funktionsweise unseres angepassten Adapters, des Datenmodells und des ListViews überprüft.

Wir haben somit alle vier Arbeitsschritte für das Verbinden von Daten und Benutzeroberfläche ausgeführt:

  1. Definieren des Aussehens der ListView-Zeilen
  2. Den ListView in das App-Layout integrieren
  3. Definieren des Datenmodells der ListView-Elemente
  4. Erstellen eines angepassten ArrayAdapters

Somit sind wir am Ende dieser Lektion angelangt. Der implementierte QuoteArrayAdapter versorgt ab jetzt unseren ListView mit sämtlichen Inhalten der angeschlossenen Datenquelle. Alle View-Objekte der ListView-Zeilen werden durch ihn mit den passenden Inhalten befüllt.

In der nächsten Lektion werden wir uns mit Event Listener von Android beschäftigen und für den Hole Daten-Button einen OnClickListener registrieren. Dadurch wird unsere App in der Lage sein Benutzereingaben, nämlich Button-Klicks, zu erfassen und gezielt darauf zu reagieren.

Weiterführende Literatur




Schreibe einen Kommentar

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