Android_Tutorial_Lektion26_fotolia_RA_Studio_46292813

Programmier Tutorial: Apps für Android entwickeln – Teil 26: Auslesen und Verarbeiten der Daten mit einem XML-Parser

Auch in dieser Lektion werden wir die vom Webserver zurück erhaltenen online Daten in unserer App weiterverarbeiten. Diesmal werden wir die Zitatdaten aus einer XML-Zeichenkette auslesen (parsen) und mit ihnen den ListView unserer Android App füllen.

Dieser Prozess wird auch im asynchronen Task ausgeführt werden, damit der UI-Thread von der Berechnung nicht blockiert wird. Dadurch bleibt die Benutzeroberfläche unserer App stets flüssig bedienbar, auch wenn die Bearbeitungszeit einmal mehrere Sekunden beträgt.


Im theoretischen Teil dieser Lektion werden wir erfahren was das XML-Format ist und mit welchen Werkzeugen XML-Daten in Android effektiv ausgelesen und weiterverarbeitet werden können. Dabei werden wir auch auf den Aufbau unserer XML-Zitatdaten genauer eingehen.

Anschließend werden wir die Parsing-Methode für XML-Daten createQuotesFromXMLString() in der Utility-Klasse implementieren. Mit ihrer Hilfe werden wir die Zitatdaten aus der vom Webserver übermittelte XML-Zeichenkette auslesen und daraus eine Quotes-Liste erzeugen.

Die neue XML-Parsing Methode lassen wir von dem asynchronen Task in der MainActivity-Klasse aufrufen, wodurch das Verarbeiten der Zitatdaten in einem eigenen Hintergrund-Thread ausgeführt wird. Damit der Webserver die Zitatdaten im XML-Format generiert, müssen wir zudem sie Startparameter des asynchronen Tasks ändern.

Abschließend werden wir unsere Android App im Emulator auf einem Android Virtual Device ausführen und prüfen, ob die erhaltenen XML-Zitatdaten korrekt ausgelesen, in eine Quotes-Liste umgewandelt und schließlich im ListView unserer App ausgegeben werden.

1. Wie XML-Daten in Android verarbeitet werden

Unsere Anwendung soll zwei verschiedene Datenformate verarbeiten können. Diese sind das JSON-Format, welchem wir uns in der vorherigen Lektion gewidmet haben, und das XML-Format, das wir in dieser Lektion behandeln werden.

Für das Übertragen der Zitatdaten von dem Webserver zu unserer Android App haben wir bisher das JSON-Format verwendet, welches für JavaScript Object Notation steht. In dieser Lektion werden wir für den Datenaustausch auf das XML-Format wechseln, welches für Extensible Markup Language (engl. für „erweiterbare Auszeichnungssprache“) steht.

Daten im XML-Format können mit relativ geringem Aufwand in Android und vielen anderen Programmiersprachen ausgelesen und weiterverarbeitet werden. Ebenso lassen sich leicht XML-Daten in Android generieren und weitergeben.

1.1 Das XML-Format im Überblick

XML ist eine der bekanntesten Auszeichnungssprachen und wird vor allem zur Darstellung hierarchisch strukturierter Daten im Format einer Textdatei, die sowohl von Menschen als auch von Maschinen lesbar ist, verwendet. Das XML-Format wird aber auch für den plattform- und implementationsunabhängigen Austausch von Daten zwischen Computersystemen eingesetzt, insbesondere für Datenübermittlung über das Internet.

Eine XML-Datei besteht aus Textzeichen und ist auch von Menschen leicht lesbar. Binärdaten enthält ein XML-Dokument per Definition nicht. Die Sprache XML wurde entwickelt, um mit ihr Daten beschreiben zu können. Im Gegensatz dazu steht die Sprache HTML, welche entwickelt wurde, um Daten darzustellen.

Der folgende XML-Code beschreibt das Inventar eines Buchladens:

<?xml version="1.0" encoding="UTF-8"?>
<Buchladen>
  <Buch Kategorie="Java">
    <Titel Sprache="de">Handbuch der Java Programmierung</Titel>
    <Autor>Guido Krüger / Heiko Hansen</Autor>
    <Jahr>2012</Jahr>
    <Preis>49.80</Preis>
  </Buch>
  <Buch Kategorie="Android">
    <Titel Sprache="de">Spieleprogrammierung mit Android Studio</Titel>
    <Autor>Uwe Post</Autor>
    <Jahr>2014</Jahr>
    <Preis>34.90</Preis>
  </Buch>
  <Buch Kategorie="Android">
    <Titel Sprache="de">Android - Der schnelle und einfache Einstieg</Titel>
    <Autor>Dirk Louis / Peter Müller</Autor>
    <Jahr>2014</Jahr>
    <Preis>29.99</Preis>
  </Buch>
</Buchladen> 

Die erste Zeile ist die XML Deklaration. Sie definiert die XML-Version, hier Version 1.0.

In der nächsten Zeile wird das Wurzelelement Buchladen des XML-Dokuments beschrieben. Jedes XML-Dokument muss genau ein Wurzelelement (root element) besitzen. Die Elemente eines XML-Dokuments formen eine Baumstruktur. Der Dokumentenbaum beginnt mit der Wurzel, dem Wurzelelement, und führt zu den Blättern, den Kinderelementen (child elements).

Das Wurzelelement liegt in der obersten Ebene. Unterhalb dieser Ebene können beliebig viele weitere Kinderelemente verschachtelt werden. Das Wurzelelement Buchladen besitzt die drei Buch-Kinderelemente. Diese drei Kinderelemente sind Geschwisterelemente.

Jedes dieser drei Geschwisterelemente besitzt das Attribut Kategorie. Der Attribut-Wert wird in Anführungszeichen nach dem = angegeben. Elemente können beliebig viele Attribute besitzen.

Jedes Buch-Kinderelement besitzt vier eigene Kinderelemente Titel, Autor, Jahr und Preis. Zwischen dem Start- und End-Tag eines Elements wird der Elementinhalt als reiner Text angegeben.

Das folgende Diagramm repräsentiert ein Buch aus dem oberen Beispiel XML-Dokument:

android_xml_format

Darstellung eines Buch-Elements aus dem oberen XML-dokument

In dem oberen Diagramm sind auch die Beziehungen der verschiedenen Elemente untereinander dargestellt. So ist der Buchladen das Vaterelement des Buchs und das Buch selbst ein Kindelement des Buchladens. Der Buchladen ist auch das Wurzelelement des XML-Dokuments.

Das Buch besitzt vier Kindelemente (Titel, Autor, Jahr und Preis) die untereinander Geschwisterelemente sind. Das Buch-Element besitzt das Attribut “Kategorie”, das den Wert Android (in der oberen Abbildung nicht dargestellt) enthält.

Für das Auslesen der XML-Daten in Android ist die genaue Kenntnis der vorliegenden Datenstruktur unerlässlich. Daher werden wir nun einen genaueren Blick auf die Struktur unserer XML-Zitatdaten werfen.

1.2 Aufbau und Struktur der XML-Zitatdaten unserer Android App

Wir werden nun die Datenstruktur der XML-Daten unserer Android App, also die Struktur der Zitatdaten, genauer untersuchen. Ziel ist es zu verstehen, wie die Zitatinformationen in dem vom Webserver erhaltenen XML-Dokument strukturiert sind, um sie später auslesen zu können.

In dem unteren Code ist der Inhalt einer typischen XML-Antwort unseres Webservers auf eine HTTP-Anfrage, wie bspw. https://www.codeyourapp.de/tools/query.php?count=3&mode=1, aufgeführt:

<query>
  <diagnostics>
    <count>3</count>
    <mode>1</mode>
    <created>2019-02-08 15:25:09</created>
  </diagnostics>
  <quotes>
    <quote>
      <id>jean_paul</id>
      <author>Jean Paul</author>
      <text>Die Leidenschaft macht die besten Beobachtungen und die ...</text>
    </quote>
    <quote>
      <id>jean_paul</id>
      <author>Jean Paul</author>
      <text>Die Wunden, die die Maschinen des Schicksals in uns schneiden ...</text>
    </quote>
    <quote>
      <id>schopenhauer</id>
      <author>Arthur Schopenhauer</author>
      <text>Es gibt nur drei Grundtriebfedern menschlicher Handlungen: Egoismus ...</text>
    </quote>
  </quotes>
</query>

In der oben angegebenen Antwort des Webservers wird im XML-Format ein Dokument definiert, welches als Wurzelelement das query-Element besitzt. Das Wurzelelement besitzt die beiden Kindelemente (child elements) diagnostics und quotes. Auf die wir nun näher eingehen werden.

Das diagnostics-Element besitzt die drei Kindelemente count, mode und created, welche für Diagnosezwecke ausgewertet werden können. Mit ihnen könnte man überprüfen, ob der Webserver die angeforderte Anzahl an Zitaten geliefert hat oder wann die Daten generiert wurden.

Für unsere Android App ist das quotes-Element von besonderem Interesse. Es enthält alle Informationen über die angefragten Zitate. Und zwar wurden vom Webserver für jedes angeforderte Zitat ein quote-Element generiert und dem quotes-Element als Kindelement zugewiesen.

Jedes dieser quote-Elemente besitzt die folgenden drei Kindelemente id, author und text. Das id-Element enthält die eindeutige Autoren-ID, das author-Element den vollständigen Namen des Autors und das text-Element den Inhalt des Zitats.

In dem folgenden Diagramm ist das XML-Format der gelieferten Zitatdaten dargestellt:

android_xml_zitatdaten

Darstellung der Datenstruktur der vom Webserver generierten XML-Zitatdaten

Möchten wir also auf die Zitatinformationen in dem oben aufgeführten XML-Dokument zugreifen, müssen wir zuerst auf das quotes-Element zugreifen und anschließend dessen Kindelemente der Reihe nach durchlaufen. Dabei können wir zu jedem quote-Kindelement die Informationen über die Autoren-ID, den Autorennamen und den Zitatinhalt auslesen und in entsprechenden Variablen zwischenspeichern.

1.3 Auslesen und Verarbeiten unserer XML-Daten in Android

Um XML-Dokumente in Android zu verarbeiten, sind verschiedene Standards verfügbar. Ein sehr oft verwendeter Standard ist JAXP (Java API for XML Processing). Von JAXP werden drei verschiedene Programmierschnittstellen zur Verfügung gestellt, die XML-Dokumente interpretieren können:

  • DOM (Document Object Model) – Die DOM-Schnittstelle ist sehr einfach aufgebaut. Sie liest das gesamte XML-Dokument aus und erstellt anschließend eine vollständige Darstellung des Dokuments im Speicher. Sie überführt auf diese Weise das XML-Dokument in eine baumartige Objektstruktur.

    Das XML-Dokument wird vom DOM-Parser, der auch DocumentBuilder genannt wird, da er eine in-memory Dokumentendarstellung erzeugt, ausgelesen. Eine Instanz der DocumentBuilder-Klasse wird durch die Factory-Klasse DocumentBuilderFactory erzeugt. Beim Parsen erstellt der DocumentBuilder zunächst eine Document-Instanz in Form einer Baumstruktur, die alle Knoten des XML-Dokuments enthält. Jeder Baumknoten in dieser Struktur implementiert die Node-Schnittstelle. Es gibt viele verschiedene Typen von Baumknoten, die die jeweiligen Datentypen aus dem XML-Dokument repräsentieren.

    Mit der DOM-API kann man in beide Richtungen arbeiten, also vom XML-Dokument zur Document-Instanz als auch vom der Document-Instanz zum XML-Dokument. Es eignet sich also nicht nur zum Parsen von XML-Dokumenten, sondern auch zum Generieren von XMLStreams oder -Dateien.

  • SAX (Simple API for XML) – Im Gegensatz zum DOM-Parser erstellt der SAX-Parser keine in-memory-Darstellung des gesamten XML-Dokumentes, was ihn schneller und weniger anspruchsvoll im Speicherverbrauch macht. Stattdessen führt der SAX-Parser eine ereignisorientierte Interpretation des XML-Dokuments durch.

    Dabei informiert der SAX-Parser den Client der XML-Dokumentenstruktur durch Rückruffunktionen (Callbacks), wodurch Methoden der DefaultHandler-Instanz, die dem Parser zur Verfügung stehen, ausgeführt werden. Am bedeutsamsten sind die ContentHandler-Methoden, implementiert durch den DefaultHandler, die aufgerufen werden, sobald der SAX-Parser auf die entsprechenden Elemente des XML-Dokumentes trifft.

    Die wichtigsten Methoden in der SAX-Schnittstelle sind:

    • startDocument() und endDocument(), die am start– und end-Tag des XML-Dokuments aufgerufen werden
    • startElement() und endElement(), die am start– und end-Tag jedes XML-Elementes aufgerufen werden
    • characters(), die mit dem sich zwischen start– und end-Tag befindlichen Inhalt des jeweiligen XML-Elements aufgerufen wird

    Mit der SAX-API kann man nur in eine Richtung arbeiten, und zwar nur vom XML-Dokument zur Darstellung in Java hin. Es eignet sich also ausschließlich zum Parsen von XML-Dokumenten. Mit der SAX-API können daher keine XMLStreams oder -Dateien generiert werden.

  • StAX (Streaming API for XML) – Seit JSE 6 ist die StAX-API Bestandteil des Java API for XML Processing Standards. Die StAX-API dient dazu, mit Hilfe sogenannter XML-PULL Parser XML-Daten zu lesen. Wie bei der SAX-API so führt auch ein StAX-Parser eine ereignisorientierte Interpretation des XML-Dokuments durch.

    Ein XML-PULL ist ähnlich einem SAX-Parser, nur dass der Parser nicht wie bei der SAX-API Informationen an die Applikation über einen Event-Mechanismus schickt (PUSH), sondern die Anwendung holt sich die nächsten Informationen selbst, wenn sie sie benötigt (PULL). StAX-Parser sind üblicherweise leistungsstärker als SAX-Parser.

Wir werden unsere XML-Zitatdaten mit der DOM-Schnittstelle verarbeiten. Der DOM-Standard lädt beim Parsen das gesamte XML-Dokument in den Hauptspeicher und stellt es dort in Form eines Objektbaums zur Verfügung. Dieser DOM-Objektbaum kann dann sehr übersichtlich in der Android App weiterverarbeitet werden.

Zwar besitzt die DOM-API den Nachteil, dass das komplette XML-Dokument im Arbeitsspeicher liegt. Jedoch ist dies nur bei sehr großen XML-Dokumenten ein Performance-Problem. In unserem Fall jedoch nicht, da unsere XML-Zitatdaten nur von sehr geringer Größe sind und daher der DOM-Objektbaum nur wenig Speicherplatz einnimmt.

In dem nächsten Abschnitt werden unsere XML-Zitatdaten durch Verwenden der DOM-API von unserer Android App parsen lassen. Dazu werden wir zuerst mit Hilfe einer Instanz der DocumentBuilders-Klasse ein DOM-Document, welches den Objektbaum repräsentiert, aus dem XML-Zitatdaten erstellen. Anschließend werden wir aus dem DOM-Document die einzelnen quote-Elemente auslesen und dadurch Zugriff auf die jeweiligen Zitatinformationen erhalten.

Wie dies im Quellcode umgesetzt wird, werden wir im nächsten Abschnitt ausführlich beschreiben, wenn wir die XML-Parsing Methode createQuotesFromXMLString() in Utility-Klasse implementieren.

2. XML-Parsing Methode in Utility-Klasse implementieren

Wir werden nun eine weitere Parsing-Methode für unsere Android App implementieren. Die neue Parsing-Methode wird vom Webserver erhaltene XML-Zitatdaten auswerten und daraus Quote-Objekte erstellen. Die erstellen Quote-Objekte werden in einer Liste abgelegt, welche schließlich an den Aufrufer zurückgegeben wird. Die so erstellte Liste mit Quote-Objekten kann dann vom ListView unserer Android App als Datenquelle verwendet werden.

Für das Verarbeiten der XML-Zitatdaten werden wir die DOM-Schnittstelle verwenden. Um sie für unsere Zwecke zu nutzen, müssen wir mehrer Klassen und Interfaces des JAXP-Standards (Java API for XML Processing) einsetzen, die sich in unterschiedlichen Packages befinden.

Damit wir den Überblick nicht verlieren, werden wir zunächst die benötigten Klassen und Interfaces kurz vorstellen und anschließend die neue XML-Parsing Methode createQuotesFromXMLString() in der Utility-Klasse implementieren.

2.1 Die für das Parsing benötigten Klassen und Interfaces des JAXP-Standards

Um unsere XML-Zitatdaten mit Hilfe der DOM-API auszulesen, werden wir den DOM-Parser des Packages javax.xml.parsers verwenden. Der DOM-Parser zerlegt den XML-Eingabestrom in seine grammatikalischen Bestandteile.

Um ihn nutzen zu können, müssen wir die folgenden drei Klassen importieren:

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

Das XML-Dokument wird vom DOM-Parser, der auch DocumentBuilder genannt wird, ausgelesen. Dabei wird eine in-memory Dokumentendarstellung in Form eines Objektbaums vom DocumentBuilder erzeugt. Um eine Instanz der DocumentBuilder-Klasse zu erzeugen, wird die Factory-Klasse DocumentBuilderFactory benötigt.

Damit der DocumentBuilder das XML-Dokument parsen kann, muss es ihm als Datenstrom übergeben werden. Dieser muss mit der InputSource-Klasse des Packages org.xml.sax aus dem XML-String erstellt werden. Zum Einlesen des Strings wird zudem die StringReader-Klasse benötigt. Da es bei der Umwandlung des XML-Strings in einen Datenstrom zu einer SAXException kommen kann, muss auch diese Exception importiert werden.

Somit müssen folgende drei Klassen importiert werden:

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.StringReader;

Der DOM-Parser liest unseren XML-String als Datenstrom ein und erzeugt daraus einen Objektbaum. Damit wir den Objektbaum verwenden können, müssen wir noch einige Interfaces des Packages org.w3c.dom importieren. Unter anderem liegt darin das Interface Document, welches den eingelesenen Objektbaum repräsentiert.

Diese folgenden drei Interfaces müssen wir importieren:

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

Beim Parsen erstellt die DocumentBuilder-Instanz zunächst ein Document-Objekt, welches alle Knoten des XML-Dokuments in Form einer Baumstruktur enthält. Jeder Baumknoten in dieser Struktur implementiert die Node-Schnittstelle. Will man mehrere Knoten auslesen, bspw. alle Kindelemente eines Knotens, so werden diese in einer NodeList gespeichert.

Wir haben nun die für das DOM-Parsing benötigten Klassen und Interfaces kennengelernt. Ein tieferes Verständnis werden wir im nächsten Schritt erlangen, wenn wir die createQuotesFromXMLString() Methode in der Utility-Klasse implementieren und mit ihr die XML-Zitatdaten mittels DOM-API parsen.

2.2 Implementieren der createQuotesFromXMLString() Methode in Utility-Klasse

Wir werden nun die Methode createQuotesFromXMLString() in der Utility-Klasse implementieren. Dazu öffnen wir die Klassendatei Utility.java im Editor von Android Studio, indem wir doppelt auf ihren Dateinamen im Project Tool Window klicken. Die Klassendatei befindet sich im Package-Ordner de.codeyourapp.zitate unseres Projekts.

In dem unteren Quellcode der Utility.java Datei sind die erforderlichen Maßnahmen bereits durchgeführt und die eingefügten Codezeilen grau markiert worden:

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_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 Utility-Klasse wurden an mehreren Stellen Änderungen vorgenommen. Die eingefügten Zeilen sind grau markiert. Wir werden nun die durchgeführten Änderungen der Reihe nach besprechen.

In den Zeilen 9 bis 17 werden die neun benötigten Klassen bzw. Interfaces des JAXP-Standards mittels Import-Anweisungen innerhalb der Utility-Klasse sichtbar gemacht, so dass wir sie ohne den Namen ihres Packages verwenden können.

In den Zeilen 128 bis 164 wird die neue Methode createQuotesFromXMLString() definiert. Sie besitzt einen Parameter vom Datentyp String, über den ihr die XML-Daten übergeben werden, und liefert als Rückgabewert eine Liste mit Quote-Objekten zurück.

Die createQuotesFromXMLString() Methode

Wir werden nun die createQuotesFromXMLString() Methode genauer betrachten. Zur Übersichtlichkeit ist die Methode an dieser Stelle nochmals aufgeführt:

public static List<Quote> createQuotesFromXMLString(String xmlString) {

    List<Quote> receivedQuoteList = new ArrayList<>();

    Document doc;
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {
        DocumentBuilder db = dbf.newDocumentBuilder();
        InputSource is = new InputSource();
        is.setCharacterStream(new StringReader(xmlString));
        doc = db.parse(is);

        // Anforderen aller Quote-Elemente als NodeList des XML-Dokuments
        NodeList allQuotesNodeList = doc.getElementsByTagName("quote");

        // Durchlaufen der NodeList und Auslesen der Daten jedes Quote-Elements
        for( int i = 0; i < allQuotesNodeList.getLength(); i++ ) {
            Node quoteNode = allQuotesNodeList.item(i);
            NodeList quoteChildNodes = quoteNode.getChildNodes();

            String imageId = quoteChildNodes.item(0).getTextContent();      // id
            String quoteAuthor = quoteChildNodes.item(1).getTextContent();  // author
            String quoteText = quoteChildNodes.item(2).getTextContent();    // text

            receivedQuoteList.add(new Quote(quoteText, quoteAuthor, imageId));
        }

    } catch (ParserConfigurationException e) {
        Log.e(TAG,"ParserConfigurationException: " + e.getMessage());
    } catch (SAXException e) {
        Log.e(TAG,"SAXException: " + e.getMessage());
    } catch (IOException e) {
        Log.e(TAG,"IOException: " + e.getMessage());
    }

    return receivedQuoteList;
}

In Zeile 3 wird die Variable receivedQuoteList deklariert und ihr ein ArrayList-Objekt zugewiesen. Die Variable ist vom Datentyp List, so dass wir später auch anstelle einer ArrayList eine LinkedList verwenden könnten. Die receivedQuoteList wird in sich die ausgelesenen Quote-Objekte aufnehmen.

In Zeile 5 legen wir die Variable doc vom Datentyp Document des org.w3c.dom Packages an. Sie wird später den aus den XML-Daten erstellten Objektbaum aufnehmen, der alle Knoten des XML-Dokuments enthält.

In Zeile 6 wird eine Instanz der DocumentBuilderFactory-Klasse erzeugt. Mit ihrer Hilfe instanziieren wir in Zeile 8 ein DocumentBuilder-Objekt, den sogenannten DOM-Parser.

Als Nächstes wird in den Zeile 9 und 10 der XML-String in einen XML-Datenstrom umgewandelt. Dazu werden die Klassen StringReader und InputSource genutzt. Von der StringReader-Klasse wird der XML-String eingelesen und daraus ein StringReader-Objekt erzeugt. Dieses Objekt wird dann der InputSource-Instanz als Datenstrom zugewiesen.

In Zeile 11 wird schließlich der XML-Datenstrom von der DocumentBuilder-Instanz ausgelesen und in ein Document-Objekt umgewandelt, das alle Knoten des XML-Dokuments enthält. Dieser Objektbaum repräsentiert die Daten des vom Webserver generierten XML-Dokuments.

In Zeile 14 fordern wir von dem doc-Objektbaum alle quote-Elemente des XML-Dokuments an. Dazu verwenden wir die getElementsByTagName() Methode, welche eine NodeList zurückliefert, die alle Elemente mit dem quote-Tag enthält. Diese Elemente repräsentieren die vom Webserver generierten Zitate. Jedes von ihnen besitzt drei Kindelemente, in denen die Autor-ID, der Autorenname und der Zitatinhalt gespeichert sind.

Mit der for-Schleife in den Zeilen 17 bis 26 durchlaufen wir die NodeList und lesen die Daten jedes quote-Elements aus. Dazu lesen wir die in der Liste enthaltenen Nodes der Reihe nach aus und fordern jeweils ihre drei Kindelemente mit der getChildNodes() Methode an.

In den Zeilen 21 bis 23 greifen wir auf den Inhalt der drei Kindelemente mit der getTextContent() Methode zu, die wir auf dem jeweiligen Kindelement aufrufen. Die zurückerhaltenen String-Werte speichern wir in den Variablen imageId, author und text zwischen. Anschließend wird in Zeile 25 ein Quote-Objekt auf Basis dieser drei ausgelesenen Zitatinformationen erzeugt und der receivedQuoteList-Liste hinzugefügt.

Nachdem alle quote-Elemente aus der NodeList allQuotesNodeList ausgelesen wurden, wird mit der return-Anweisung in Zeile 36 die Methode verlassen und als Rückgabewert die mit Quote-Objekten gefüllte receivedQuoteList-Liste an den Aufrufer übergeben.

Mit diesen Quellcodezeilen haben wir die Parsing-Methode createQuotesFromXMLString() implementiert. Sie wird für uns die vom Webserver erhaltenen XML-Daten auslesen und daraus eine Liste mit Quote-Objekten erstellen. Alles was wir ihr dazu übergeben müssen, ist der XML-String mit den Zitatinformationen.

In Android Studio sollte der Inhalt der Utility.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 Utility.java Klassendatei dargestellt. Dem Quellcode wurden neun Import-Anweisungen und die createQuotesFromXMLString() Methode hinzugefügt. Es ist nur die hinzugefügte Methode aufgeklappt. Die drei anderen Methoden wurden nicht verändert und sind daher zugeklappt.

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

  1. A – Die benötigten Import-Anweisungen zum Sichtbarmachen der benötigten Klassen des JAXP-Standards.
  2. B – Die createQuotesFromXMLString() Methode zum Auslesen und Verarbeiten der XML-Zitatdaten vom Webserver.

Da wir jetzt die createQuotesFromXMLtring() Methode in der Hilfsklasse Utility erstellt haben, können wir als Nächstes den Parsing-Prozess, das Verarbeiten des XML-Strings, von unserer App durchführen lassen. Dazu sind zwei kleine Änderung an der MainActivity-Klasse vorzunehmen.

3. Starten des XML-Parsing Prozesses in der MainActivity-Klasse

Wir haben nun die Parsing-Methode für XML-Daten in der Utility-Klasse implementiert. Unsere Anwendung ist somit in der Lage die vom Webserver erhaltenen XML-Zitatdaten auszulesen und daraus eine Liste mit Quote-Objekten zu erzeugen. Diesen Parsing-Prozess werden wir von dem asynchronen Task durchführen lassen, welcher durch die RequestQuotesTask-Klasse implementiert wird.

Und zwar werden wir in der doInBackground() Methode der Klasse RequestQuotesTask die XML-Parsing Methode createQuotesFromXMLString() aufrufen und ihr als Argument den XML-String mit den Zitatdaten übergeben. Damit wir ihr die Zitatdaten als XML-String übergeben können, müssen wir vorher den Webserver anweisen, statt des JSON-Formats nun das XML-Format für die Generierung der Zitatdaten zu verwenden.

Somit werden folgende Änderungen vorgenommen:

  1. Den Webserver anweisen die Zitatdaten im XML-Format zu generieren – Dazu müssen wir eine Änderung an der refreshListView() Methode in der MainActivity-Klasse vornehmen. Und zwar muss beim Starten des asynchronen Task als Parsing-Modus die XML-Parsing Methode festgelegt werden.

  2. Hinzufügen des Aufrufs der XML-Parsing Methode – Diese Änderung wird in der inneren Klasse RequestQuotesTask, welche den asynchronen Task implementiert, der MainActivity-Klasse durchgeführt. Dazu muss in der doInBackground() Methode der RequestQuotesTask-Klasse die switch-Anweisung so erweitert werden, dass die im vorherigen Abschnitt erstellte createQuotesFromXMLString() Methode aufgerufen wird, wenn XML-Daten verarbeitet werden sollen. An der entsprechenden Stelle ist bereits ein Kommentar in der vorherigen Lektion als Platzhalter hinterlassen worden.

Um die oben beschriebenen Änderung am asynchronen Task vorzunehmen, überarbeiten wir nun die innere Klasse RequestQuotesTask der MainActivity-Klasse. Dazu öffnen wir die Klassendatei MainActivity.java im Editor von Android Studio mit einem Doppelklick auf ihren Dateinamen im Project Tool Window. Die Klassendatei befindet sich im Package-Ordner de.codeyourapp.zitate unseres Projekts.

In dem unten aufgeführten Quellcode der inneren Klasse RequestQuotesTask der MainActivity.java Datei wurden die beiden Änderungen bereits durchgeführt. Der Webserver wurde angewiesen nun XML-Zitatdaten zu generieren und die switch-Anweisung wurde um den Aufruf der createQuotesFromXMLString() Methode erweitert.

Die beiden überarbeiteten Codezeilen Zeile 166 und Zeile 193 sind grau markiert 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.

An oben aufgeführtem Quellcode der MainActivity-Klasse und ihrer inneren Klasse RequestQuotesTask wurden zwei Änderungen vorgenommen. Dazu wurden die Methoden refreshListView() und doInBackground() leicht überarbeitet. Auf die vorgenommenen Änderungen werden wir nun noch einmal kurz eingehen.

Änderung 1: In der refreshListView() Methode

In Zeile 166 wurde die Start-Anweisung des asynchronen Tasks so angepasst, dass nun die Zitatdaten vom Webserver im XML-Format generiert und statt 10 nun 8 Zitate angefordert werden. Auf diese Weise können wir sofort an der Anzahl der ListView-Einträge erkennen, ob auch wirklich XML-Daten verwendet werden.

Zur besseren Übersichtlichkeit ist die überarbeitete refreshListView() Methode hier nochmals ausgeführt:

private void refreshListView() {
    // Instanziieren des AsyncTask-Objekts und Starten des asynchronen Tasks
    RequestQuotesTask requestQuotesTask = new RequestQuotesTask();
    requestQuotesTask.execute(8, Utility.XML_PARSING_METHOD);
}

Änderung 2: In der switch-Anweisung der doInBackground() Methode

Die zweite Änderung wurde in der Zeile 193 an der switch-Anweisung in der doInBackground() Methode der inneren Klasse RequestQuotesTask vorgenommen. Dazu wurde für den zweiten Fall (case Utility.XML_PARSING_METHOD), wenn als Parsing-Modus die XML-Parsing Methode verwendet wird, der Methodenaufruf createQuotesFromXMLString() hinzugefügt.

Die überarbeitete switch-Anweisung ist zur besseren Übersichtlichkeit hier nochmals ausgeführt:

switch (parsingMethod) {
    case Utility.JSON_PARSING_METHOD:
        newQuoteList = Utility.createQuotesFromJSONString(quotesString);
        break;
 
    case Utility.XML_PARSING_METHOD:
        // Hier fügen wir nun den Methodenaufruf der XML-Parsing Methode ein
        newQuoteList = Utility.createQuotesFromXMLString(quotesString);
        break;
}

Durch die Erweiterung der switch-Anweisung kann unsere Android App jetzt sowohl JSON– als auch XML-Daten zu verarbeiten. Welche Parsing-Methode verwendet wird, ist von den angeforderten Zitatdaten abhängig. Werden JSON-Daten vom Webserver angefordert, wird die JSON-Parsing Methode aufgerufen. Werden XML-Daten angefordert, wie es in dieser Lektion der Fall ist, wird die XML-Parsing Methode aufgerufen.

Außer dem Überarbeiten der refreshListView() Methode und dem Erweitern der switch-Anweisung der doInBackground() Methode müssen keine weiteren Änderungen an der MainActivity– bzw. ihrer inneren Klasse vorgenommen werden.

In Android Studio sollte die 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 nur in der refreshListView() und doInBackground() Methode überarbeitet. Daher sind diese beiden Methoden als einzige aufgeklappt worden. Alle anderen Methoden bleiben geschlossen.

In der refreshListView() Methode wurde die Start-Anweisung des asynchronen Tasks so angepasst, dass nun acht Zitate vom Webserver im XML-Format angefordert werden. Dazu wurde die Argumente des Methodenaufrufs angepasst. Der Methodenaufruf erfolgt in der blau unterstrichene Codezeile (Markierung A) der refreshListView() Methode.

In der switch-Anweisung der doInBackground() Methode wurde der asynchrone Task so überarbeitet, dass er nun auch das Parsing der XML-Daten durchführt. Dazu wurde der Methodenaufruf der createQuotesFromXMLString() (Markierung B) an die entsprechende Stelle in der switch-Anweisung eingefügt.

Führt der Benutzer nun die Swipe-Down Geste durch oder klickt auf den Action-Button in der App Bar, wird die refreshListView() Methode aufgerufen, von welcher der asynchrone Task gestartet wird. Der asynchrone Task startet daraufhin die HTTP-Anfrage, welche nun XML-Daten anfordert, und führt anschließend das Auslesen der vom Webserver erhaltenen XML-Zitatdaten durch. Bei diesem Parsing-Prozess wird eine Quote-Liste erzeugt und dem ListView unserer Android App als neue Datenquelle zugewiesen.

Wie dies zur Laufzeit auf einem Android Gerät aussieht, werden wir im nächsten Abschnitt erfahren.

4. Ausführen und Testen unserer Android App

Wir werden nun unserer Android App auf einem Android Virtual Device im Emulator ausführen lassen. Unsere Anwendung kann nun echte online Daten im JSON– und XML-Format von einem Webserver anfordern, intern auswerten und anschließend auf dem Display in dem ListView darstellen. Ob alles wie erwartet funktioniert, wollen wir nun überprüfen, indem wir mit einer Swipe-Down Geste den asynchronen Task starten.

Bevor wir unsere App auf dem Android Gerät ausführen lassen, müssen wir diese unbedingt vorher manuell von dem Android Virtual Device deinstallieren. Die benötigte Berechtigung (Internetzugriff) wird erst korrekt vom Android System erteilt, wenn vorher eine komplette Deinstallation unserer Android App stattgefunden hat. Danach kann die App neu auf das Android Gerät installiert und ausgeführt werden.

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

Sobald unsere App auf dem AVD gestartet wurde, führen wir die Swipe-Down Geste durch oder klickt auf den Action-Button in der App Bar. Dadurch wird die refreshListView() Methode aufgerufen, von welcher der asynchrone Task gestartet wird. Der asynchrone Task stellt daraufhin sofort die HTTP-Anfrage, welche diesmal XML-Daten vom Webserver anfordert.

Wichtiger Hinweis: Falls die Fehlermeldung socket failed: EPERM (Operation not permitted) in der Logcat-Ausgabe erscheint, liegt das an einem Bug des Android Emulators in Verbindung mit Instant Run. Um diesen Fehler zu beheben, muss die Zitate-App zuerst manuell von dem AVD deinstalliert und anschließend mit Run > Run ‚app‘ wieder auf dem Gerät ausgeführt werden.

Die vom Server übermittelten XML-Daten werden anschließend ausgelesen und für den ListView aufbereitet, indem eine Quote-Liste anhand der Zitatinformationen erzeugt wird. Sobald die Quote-Liste erstellt wurde, wird sie dem ListView als neue Datenquelle zugewiesen.

In der unteren Abbildung ist unsere Android App kurz nach Ausführen der Swipe-Down Geste zu sehen:

screenshot_xml_parsing

Diesmal wurden XML-Daten vom asynchronen Task angefordert, ausgewertet und im ListView ausgegeben.

Der asynchrone Task hat bereits die HTTP-Anfrage ausgeführt, die vom Webserver erhaltenen XML-Daten ausgewertet und die Quote-Liste erstellt sowie diese dem ListView als neue Datenquelle zugewiesen. Auf dem Bildschirm werden die so übertragenen Zitate auch schon in Form von ListView-Einträgen ausgeben. In der Liste sind diesmal acht Zitate enthalten, so viele wie in der HTTP-Anfrage angefordert wurden.

Bei dem Parsing-Prozess werden zwei Log-Meldungen von unserer Android App an die Konsole ausgegeben. Diese können wir im Logcat Tool Window von Android Studio folgendermaßen betrachten:

  1. Wir öffnen das Logcat Tool Window mit einem Klick auf den Logcat-Tab am unteren Bildschirmrand.
  2. In der Drop-Down Liste stellen wir die Prioritätsstufe auf Verbose ein.
  3. In das Suchfeld geben wir Utility|RequestQuotesTask (ohne Leerzeichen) als Suchbegriff ein.
  4. Für die hintere Drop-Down Liste stellen wir sicher, dass der Eintrag No Filters ausgewählt ist.
logcat_http_xml_output

Die Anfrage-URL und erhaltenen XML-Zitatdaten im Logcat Tool Window von Android Studio betrachten

In der oberen Abbildung ist die Logcat-Ausgabe unserer Android App zu sehen. Der asynchrone Task hat seine Arbeit gerade abgeschlossen, die HTTP-Anfrage wurde an den Webserver gestellt und auch bereits die XML-Antwort erhalten. Wie zu erkennen ist, hat die Utility-Klasse die Anfrage-URL (Markierung A) korrekt erstellt.

Auch die Antwort des Webservers ist in der oberen Abbildung zu sehen. Sie besteht aus Diagnose- und Zitatdaten (Markierung B) und wird in Form einer XML-Zeichenkette von der RequestQuotesTask-Klasse ausgegeben.

Zusammenfassung

Auch in dieser Lektion haben wir die vom Webserver zurück erhaltenen online Daten in unserer App weiterverarbeitet. Diesmal haben wir die Zitatdaten aus einer XML-Zeichenkette ausgelesen und mit ihnen den ListView unserer Android App gefüllt. Der Parsing-Prozess wurde dabei im asynchronen Task ausgeführt, damit der UI-Thread von der Berechnung nicht blockiert wird.

Im theoretischen Teil dieser Lektion haben wir erfahren was das XML-Format ist und mit welchen Werkzeugen XML-Daten in Android effektiv ausgelesen und weiterverarbeitet werden können. Dabei sind wir auch auf die Datenstruktur unserer XML-Zitatdaten genauer eingegangen.

Anschließend haben wir die Parsing-Methode für XML-Daten createQuotesFromXMLString() in der Utility-Klasse implementiert. Mit ihrer Hilfe haben wir die Zitatdaten aus der vom Webserver übermittelte XML-Zeichenkette ausgelesen und daraus eine Quotes-Liste erzeugen lassen. Die so erstellte Liste wird anschließend an den Aufrufer zurückgeliefert und schließlich dem ListView unserer Android App als neue Datenquelle zugewiesen.

Die neue XML-Parsing Methode wird vom asynchronen Task in der MainActivity-Klasse aufgerufen, wodurch das Verarbeiten der Zitatdaten in einem eigenen Hintergrund-Thread ausgeführt wird. Damit der Webserver die Zitatdaten im XML-Format generiert, mussten wir zudem sie Startparameter des asynchronen Tasks ändern.

Abschließend haben wir unsere Android App im Emulator auf einem Android Virtual Device ausgeführt und überprüft, ob die erhaltenen XML-Zitatdaten korrekt ausgelesen, in eine Quotes-Liste umgewandelt und schließlich im ListView unserer Android App ausgegeben werden.

In der nächsten Lektion werden wir den Lebenszyklus von Android Anwendungen, den sogenannten Android Lifecycle, kennenlernen. Dabei werden wir die verschieden Stufen beschreiben, die unsere Android App während ihres Lebens durchschreitet. Dieses spannende Thema ist gerade für die Entwicklung komplexer Apps von zentraler Bedeutung.

Weiterführende Literatur




Comments 25

  1. Hi Chris,

    auch von mir vielen Dank für die Mühe, die in diesem Tutorial steckt.
    Da ich nicht von einer festen Position der einzelnen Elemente im XML ausgehen wollte, habe ich versucht in einer Switch-Verzweigung auf den Nodenamen zu reagieren. Allerdings hat aktienParameter.getFirstChild().getNodeName() stets nur den String #text zurückgegeben.
    Nach etwas rumprobieren hat dann das Umwandeln des Node in ein Element funktioniert:

    Element el = (Element)aktienParameter;
    switch (el.getTagName()){
             case "symbol": ...
    

    Sollte das Abfragen mit getNodeName() nicht auch funktionieren?

    Viele Grüße,
    Robert

    1. Post
      Author

      Hallo Robert,

      danke für die lobenden Worte!

      Es scheint, als würde die Methode getNodeName() nur bestimmte Werte abhängig vom Node-Typen zurückliefern. Aus der Node-Referenz auf Developer.Android.com bin ich aber auch nicht so richtig schlau geworden.

      Viele Grüße, Chris

  2. Ich bin im Kapitel 9 angelangt. Die Meldung „Aktiendaten vollständig geladen“ wird angezeigt, aber die Daten werden nicht geladen. Ist Ihr Server down oder habe einen Fehler produziert?

    Besten Dank für die sehr gute Anleitung.

    1. Post
      Author
  3. Hallo Zusammen

    Auch von mir möchte ich hier ein Lob richten, es hilft mir mich mit Android Studio zu recht zu kommen.
    Als blutiger Programmieranfänger habe ich leider nicht leicht zu verstehen, was die einzelnen „Befehle“ genau bewirken und wie man genau weiss, welche Befehlsoperatoren angewendet werden muss resp. wie man sie genau so schreibt.
    Ich hab jetzt den ganzen Code kopiert und im Studio eingefügt, leider erhalte ich immer diese Meldung:

    Error running app: Instant Run requires ‚Tools | Android | Enable ADB integration‘ to be enabled

    Wenn ich im App auf „Aktualisieren“ klicke, so stürzt die App ab.

    Ich bin euch sehr dankbar, wenn ihr hier mir weiterhelfen könnt.

    Als blutiger Anfänger habe ich auch meine Schwierigkeiten, wie ich starten soll resp. wonach ich suchen/eingeben soll. Google weiss/findet alles, ist mir bewusst :). Deshalb nebenbei bemerkt: Wo kann ich mich noch besser vorbereiten, so dass mir diverse Beschriftungen nicht komplett unverständlich erscheinen.

    Vielen Dank nochmals und finde es sehr gut, dass die Zugänglichkeit für jeden gewährleistet ist :).

    Gruss Pi

  4. Hi Chris,

    auch von meiner Seite erst einmal großes Dankeschön für die Tutorials.

    Bis jetzt kam ich eigentlich gut durch, alles hat funktioniert. Anfänglich auch mit diesem Tutorial (Aktiendatenliste anzeigen, aktualisieren drücken, nur noch 3 Einträge mit mehr Details). Als ich heute weiter machen wollte, hat bei Start der App und aktualisieren das Anzeigen der 3 Einträge geklappt. Als ich die App schloss und wieder aktualisierte, änderte sich außer „Aktiendaten werden abgefragt!“ und „Aktiendaten vollständig geladen!“ nichts mehr. Also die 9 Einträge vom „Startbildschirm“ blieben die gleichen (mit z. B. „Adidas – Kurs: 73,45 €“).

    Daraufhin habe ich einmal die App vom Tablet gelöscht und wieder neu draufgespielt, nochmals den gesamten Quellcode von „AktienlisteFragment.java“ neu eingefügt und kompiliert, aber ohne Erfolg. Ins Internet (via chrome-Button) komme ich auch…

    Irgendeine Idee, was das sein könnte oder wie ich dieses Problem analysieren könnte?

    Schaue ich währen der Bedienung ins „Run“-Protokoll rein, wird mir folgender Fehler angezeigt:

    E/HoleDatenTask: Error 
    java.io.FileNotFoundException: https://query.yahooapis.com/v1/public/yql?
    q=select%20*%20from%20csv%20where%20url='http://download.finance.yahoo.com/d/quotes.csv?
    s=BMW.DE,DAI.DE,%255EGDAXI%26f=snc4xl1d1t1c1p2ohgv%26e=.csv'%20and%20columns=
    'symbol,name,currency,exchange,price,date,time,change,percent,open,high,low,volume'&amp;diagnostics=true
     at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:186)
     at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:246)
     at de.programmierenlernenhq.aktiehq.app.AktienlisteFragment$HoleDatenTask.doInBackground(AktienlisteFragment.java:243)
     at de.programmierenlernenhq.aktiehq.app.AktienlisteFragment$HoleDatenTask.doInBackground(AktienlisteFragment.java:136)
     at android.os.AsyncTask$2.call(AsyncTask.java:288)
     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
     at java.lang.Thread.run(Thread.java:848)
    

    Schon mal vielen Dank für deine Zeit
    Adventliche Grüße
    Sebastian

    1. Problem möglicherweise erledigt. Frei nach dem Windows-Prinzip zur Problembehandlung: Aus-An-Geht…
      Dennoch zur Problemanalyse, wie kann ich dieses denn untersuchen? Anhand der Log-Daten? Wenn ja, worauf muss ich achten und nach was googlen?

      Nochmals Gruß

    2. Post
      Author

      Hallo Sebastian,

      gut wenn es jetzt wieder bei dir funktioniert.

      Die Fehlerursache findet man mit Hilfe des Debuggers von Android Studio. Man setzt einen Breakpoint an die Zeile im Quellcode, die als letzte vor dem Absturz fehlerfrei ausgeführt wurde und geht dann Step-by-Step vor. Solange bis man den Fehler lokalisiert hat. Im Debugger kann man dabei genau nachverfolgen, welchen Wert welche Variable besitzt und so feststellen was schief läuft. Falls du Debugging noch nicht so gut kennst, kannst du ja mal danach googeln. Es gibt bestimmt einige hilfreiche Videos bzgl. Debugging in Android Studio.

      Viele Grüße, Chris

  5. Hallo Chris,

    kann ich stattdessen .getTextContent() verwenden?

    So bekomme ich keinen Fehler:
    aktienParameterWert = aktienParameter.getTextContent();

    Vielen Dank für dein Tutorial!

    1. Post
      Author

      Hallo Tom,

      müsste man testen, ob getTextContent() genutzt werden kann. Könnte klappen.

      Viele Grüße, Chris

  6. Bei mir führt Zeile 37 zu einem Fehler:
    java.lang.NullPointerException: Attempt to invoke interface method ‚java.lang.String org.w3c.dom.Node.getNodeValue()‘ on a null object reference

    37 aktienParameterWert = aktienParameter.getFirstChild().getNodeValue();

    Das Element hat ja kein Child, also liefert .getFirstChild() null, daher der Fehler oder?

    1. Post
      Author

      Hallo Tom,

      wenn der Rückgabewert (Objekt) von getFirstChild() leer ist, also ein null object, dann führt dies zu deiner angegebenen Fehlermeldung. Dies sollte aber normalerweise nicht passieren. Der Inhalt der Variable aktienParameterWert scheint nicht die korrekten Daten zu enthalten.

      Viele Grüße, Chris

  7. Hey Chris
    fällt dir zu diesem Fehler etwas ein?
    04-05 11:04:18.801 2035-2063/ch.test.aktiehq.app E/Surface: getSlotFromBufferLocked: unknown buffer: 0xab3d1220
    04-05 11:04:20.300 2035-2063/ch.test.aktiehq.app E/Surface: getSlotFromBufferLocked: unknown buffer: 0xab3d24f0

    er erscheint im terminal, sobald ich auf Aktualisieren drücke.
    das „Aktiendaten werden abgefragt“ Toast kommt aber noch..

    Merci für deine Hilfe
    Liebe Grüsse

    Claudia

  8. Zunächst einmal, klasse Tutorial! Das beste, dass ich zum Einstieg in Android finden konnte.

    Eine Sache ist mir jedoch unklar. Wieso wird nach der Methode onPostExecute die Liste automatisch aktuallisiert? Wir haben zwar mit „mAktienlisteAdapter.add(aktienString);“ die Strings zum Adapter hinzugefügt, aber das aktualisiert die sichtbare Liste doch nicht automatisch, oder?

    1. Post
      Author

      Hallo Hans,

      danke für Dein Lob!

      Die Methode add() informiert den verbundenen View selbständig und dieser aktualisiert sich dann auch von selbst. Das ist standardmäßig so in Android implementiert. Mit der Methode setNotifyOnChange() kann dies für den ArrayAdapter deaktiviert werden. Siehe folgender Link:

      ArrayAdapter

      Viele Grüße, Chris

  9. Hallo Chris,
    nachdem ich vor einiger Zeit hier mal das Projekt Aktiendaten nachgebaut habe und das auch sehr gut funktioniert hat, habe ich mir gedacht, es sollte für mich auch möglich sein eine eigene App zu bauen, die Wetterdaten, die auf meinem Webspace liegen, auslesen zu können und in einer eigenen App darzustellen.
    Ich komme jetzt soweit, daß ich die Daten in meine App hochladen kann, dann wird meine App allerdings angehalten.
    Im Log ist eine FATAL EXCEPTION nachzulesen
    02-21 15:47:09.760: E/AndroidRuntime(26009): FATAL EXCEPTION: AsyncTask #1
    und noch etliche andere Meldungen hinterher.
    Wie kann ich jetzt bei der Fehlersuche vorgehen?
    Kannst du etwas empfehlen?

    Grüße
    Mathias

    1. Post
      Author

      Hallo Mathias,

      meist wird der Fehler ziemlich exakt in dem Error-Log angegeben.

      Wenn Du möchtest, kannst Du mir den gesamten Error-Log per E-Mail zuschicken und ich schau ihn mir mal genauer an. Die E-Mail Adresse steht im Impressum.

      Viele Grüße, Chris

    2. Super, Mail ist schon unterwegs.
      Vielen Dank im voraus.

      Grüße
      Mathias

  10. Hallo,

    ich habe mich bis zu diesem Abschnitt vorgearbeitet. Dass mir das gelungen ist, verdanke ich der ausgezeichneten Darstellung dieses Lehrstoffes, für den ich mich herzlich bedanke.

    Jetzt habe ich aber ein Problem, für das ich selbst keine Lösung finde.

    In der Methode leseXmlAktiendatenAus() wird für den Aufruf von Log.e als erster Parameter LOG_TAG übergeben. Wo und wie ist LOG_TAG definiert?

    Danke für eine Antwort,
    Konrad

    PS: Habe es in der Methode onCreateView() gefunden. Jetzt muss ich nur noch dahinter kommen, warum es dann in leseXmlAktiendatenAus() nicht gefunden wird.

    1. Post
      Author

      Hallo Konrad,

      vielen Dank für Dein Lob!

      Die Konstante LOG_TAG wird in der inneren Klasse HoleDatenTask der Klasse AktienlisteFragment definiert. Der gesamt Quellcode der Klasse AktienlisteFragment ist leider nicht in Teil 9 angegeben, sondern nur auf die Klassendatei verlinkt worden.

      Am besten Du speicherst die Klassendatei AktienlisteFragment.java auf Deinem Rechner ab und analysiert den Quellcode. Darin wird in Zeile 129 der LOG_TAG definiert.

      Viele Grüße, Chris

    2. Danke Chris,

      danke für Deine Information. Jetzt ist alles klar. Bei der Übernahme des Codes für die innere Klasse HoleDatenTask (hier Abschnitt 3.2) mussten ja einige Zeilen ab der 2. Zeile in dieser Klasse überschrieben werden. Ich habe aber ab der ersten Zeile überschrieben und das ist die mit der Definition für LOG_TAG.

      Diese Definition ist aber auch in der Methode CreateView() (Zeile 88) vertreten. Von dort habe ich sie mir in die Klasse HoleDatenTask geholt.

      Es grüßt Dich aus Landsberg, Konrad

    3. Post
      Author
  11. Pingback: Android Tutorial: Activities und Intents in Android

  12. Pingback: Android Tutorial: Daten von einer Webseite abfragen in Android

Schreibe einen Kommentar

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