Android_Tutorial_Lektion24_fotolia_RA_Studio_46292813

Programmier Tutorial: Apps für Android entwickeln – Teil 24: Daten über das Internet von einem Webserver abfragen

Wir werden in dieser Lektion mit unserer Android App auf einen Webserver zugreifen. An den Server werden wir eine HTTP-Anfrage stellen und als Antwort echte online Daten erhalten. Für die Anfrage werden wir den, in der vorherigen Lektion erstellten, asynchronen Task nutzen.

Auf diese Weise ist sichergestellt, dass der UI-Thread nicht von der Anfrage blockiert wird und somit die Benutzeroberfläche unserer Anwendung stets flüssig bedienbar bleibt. Auch wenn die Antwortzeit einmal mehrere Sekunden betragen sollte.


Als Antwort werden wir vom Webserver eine Zeichenkette, also einen String, erhalten. In diesem String sind die Daten von mehrere Zitat-Objekte im JSON-Format enthalten. Die Daten wird unsere Android App dann nutzen, um den ListView auf Anforderung des Benutzers mit neuen Zitaten zu füllen. Später werden wir vom Webserver wahlweise auch die Daten im XML-Format anfordern können.

Was die JSON– und XML-Formate genau sind und wofür sie verwendet werden, werden wir in den nächsten beiden Lektionen ausgiebig besprechen, wenn wir die erhaltenen JSON– bzw. XML-Daten in unserer App auswerten und weiterverarbeiten werden. In dieser Lektion werden wir unseren Fokus hauptsächlich auf die HTTP-Anfrage selbst richten.

Dazu werden wir im theoretischen Teil dieser Lektion den Serveranfrage im Allgemeinen betrachten und klären welche Bedingungen von unserer App für das Ausführen eines HTTP-Requests erfüllt werden müssen. Dabei werden wir auch die Sicherheitsarchitektur des Android Systems näher kennenlernen.

Anschließend werden wir im praktischen Teil dieser Lektion die Genehmigung für die HTTP-Anfrage für unsere App einholen und danach die Serveranfrage in einer eigenen Klasse, der Utility-Klasse, implementieren. Die Utility-Klasse ist als Hilfsklasse konzipiert, die bestimmte allgemeine Aufgaben übernimmt und durch die der Quellcode unserer Anwendung übersichtlicher wird.

Die HTTP-Anfrage werden wir von dem asynchronen Task in der MainActivity-Klasse durchführen lassen. Dadurch ist sichergestellt, dass der UI-Thread nicht von der Anfrage blockiert, sondern diese in einem eigenen Hintergrund-Thread abgearbeitet wird.

Abschließend werden wir unsere Android App im Emulator auf einem Android Virtual Device ausführen und eine HTTP-Anfrage an den Webserver stellen. Die vom Server generierte Antwort werden wir dann im Logcat Tool Window von Android Studio analysieren und prüfen, ob die Daten korrekt übertragen wurden.

1. Das App Permissions System von Android

Ein wichtiger Designansatz der Sicherheitsarchitektur von Android ist, dass keine App die Erlaubnis besitzt, schadhafte Operationen auf andere Anwendungen, das Betriebssystem oder die Benutzerdaten auszuführen. Dies beinhaltet Aktionen wie:

  • Lesen oder Überschreiben der privaten Benutzerdaten (Kontakte, E-Mails oder SMS)
  • Lesen oder Überschreiben der Dateien anderer Anwendungen
  • Lesen oder Ändern der Wi-Fi oder Bluetooth Konfiguration
  • Zugriff auf Kamera, Mikrophon und andere Sensoren
  • Netzwerkzugriffe ausführen

Jede Android App wird dadurch in einer Prozess Sandbox, einem isolierten Bereich, innerhalb dessen jede Maßnahme keinerlei Auswirkung auf die äußere Umgebung hat, ausgeführt. Möchte eine App zusätzliche Fähigkeiten erlangen, muss sie dafür um Erlaubnis fragen. Auf diese Weise werden die Privatsphäre des Nutzers geschützt und schadhafte Operationen verhindert.

Abhängig von der Art der angeforderten Funktion wird die Berechtigung dafür entweder automatisch bei der Installation der Android App genehmigt oder der Benutzer aufgefordert, die Anfrage manuell zu genehmigen. Erteilt der Nutzer die Berechtigung nicht, kann die App auf die entsprechende Ressource oder entsprechenden Benutzerdaten nicht zugreifen.

1.1 Genehmigung (Erlaubnis) für geschützte Funktionen einholen

Möchte eine Android App geschützte Funktionen nutzen, muss sie vorher die dafür erforderlichen Berechtigungen einholen. Dazu muss sie in dem App Manifest, der AndroidManifest.xml Datei, mit Hilfe des <uses-permission> Tags bekanntgeben, welche Berechtigungen sie für das Verrichten ihrer Arbeit benötigt.

Eine App die Zugriff auf das Internet benötigt, würde um folgende Genehmigung bitten:

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="de.codeyourapp.zitate">

    <!-- Diese Genehmigung wird für das Öffnen von Network Sockets benötigt. -->
    <uses-permission android:name="android.permission.INTERNET"/>

    <application ...>

        ...

    </application>

</manifest>

Wenn von der App nur normale Berechtigungen in dem App Manifest auflistet werden, also Berechtigungen, die kein großes Risiko für die Privatsphäre des Benutzers oder den Betrieb des Geräts darstellen, erteilt das Android System diese Berechtigungen automatisch bei der Installation der Anwendung.

Sind in dem App Manifest gefährliche Berechtigungen auflistet, also Berechtigungen, die die Privatsphäre des Benutzers oder den normalen Betrieb des Geräts beeinträchtigen könnten, wie bspw. der Zugriff auf die Kontakte des Benutzers, muss der Anwender diesen Berechtigungen explizit die Zustimmung erteilen.

1.2 Berechtigungen auf unterschiedlichen Android Geräten erteilen

In Android sind Berechtigungen in verschiedene Sicherheitsstufen unterteilt. Dabei wird hauptsächlich zwischen normalen und gefährlichen Berechtigungen unterschieden. Die Sicherheitsstufe einer Berechtigung entscheidet darüber, ob der Benutzer die Erlaubnis explizit erteilen muss oder die Berechtigung automatisch vom Android System gewährt wird.

Hinweis: Android stellt eine große Menge an Berechtigungen zur Verfügung, die in Manifest.permission definiert sind. Eine aktuelle Übersicht über die möglichen Berechtigungen des Android Systems, zusammen mit kurzen Erklärungen, ist auf der Android Developer Webseite angegeben.

Die Art und Weise, wie Android den Benutzer auffordert, gefährliche Berechtigungen zu erteilen, hängt von der Android Version ab, die auf dem Gerät des Benutzers ausgeführt wird, und der Systemversion, für die die App entwickelt wurde.

Normale Berechtigungen umfassen Bereiche, in denen die Anwendung auf Daten oder Ressourcen außerhalb der App Sandbox zugreifen muss, in denen jedoch nur ein sehr geringes Risiko für die Privatsphäre oder den Betrieb anderer Apps besteht. Beispielsweise ist die Berechtigung zum Festlegen der Zeitzone eine normale Berechtigung.

Wenn eine App in ihrem App Manifest erklärt, dass sie eine normale Berechtigung benötigt, erteilt das Android System der App automatisch diese Berechtigung zum Zeitpunkt der Installation. Das System fordert den Benutzer nicht auf, normale Berechtigungen zu erteilen, und Benutzer können diese Berechtigungen nicht widerrufen. Diese Vorgehensweise wurde erst mit Android 6.0 eingeführt.

Gefährliche Berechtigungen umfassen Bereiche, in denen die App Daten oder Ressourcen benötigt, die private Informationen des Benutzers enthalten, oder möglicherweise die gespeicherten Daten des Benutzers oder den Betrieb anderer Apps beeinflussen können. Zum Beispiel ist die Fähigkeit, die Kontakte des Benutzers zu lesen, eine gefährliche Berechtigung.

Wenn eine App in ihrem App Manifest erklärt, dass sie eine gefährliche Berechtigung benötigt, muss der Benutzer der App explizit die Berechtigung erteilen. Damit er dies vornehmen kann, muss die App den Benutzer zur Laufzeit auffordern die Berechtigung zu erteilen.

1.2.1 Berechtigungen zur Laufzeit erteilen (Android 6.0 und neuer)

Wenn auf dem Gerät Android 6.0 (API Level 23) oder höher ausgeführt wird und die targetSdkVersion der App 23 oder höher ist, wird der Benutzer nicht zu jeder Zeit über App Berechtigungen informiert. Die App muss den Benutzer explizit bitten, die entsprechende gefährliche Berechtigung zur Laufzeit zu gewähren.

Wenn die App eine gefährliche Berechtigung anfordert, wird dem Benutzer ein Systemdialog angezeigt, der ihm mitteilt, auf welche Berechtigungsgruppe die App zugreifen möchte. Der Dialog enthält eine Schaltfläche zum Ablehnen und Zulassen. Der Benutzer kann sich diesen Dialog wiederholt anzeigen oder seine Antwort dauerhaft speichern lassen.

Eine einmal erteilte Berechtigung kann vom Benutzer auch wieder zurückgenommen werden. Daher muss zur Laufzeit immer geprüft werden, ob die benötigte gefährliche Berechtigung auch tatsächlich erteilt worden ist und nicht zwischenzeitlich zurückgenommen wurde. Prüft man dies nicht, tritt eine SecurityException ein.

1.2.2 Berechtigungen bei der Installation erteilen (Android 5.1.1 und älter)

Wenn auf dem Gerät Android 5.1.1 (API Level 22) oder niedriger ausgeführt wird oder die targetSdkVersion der App 22 oder niedriger ist, fordert das System den Benutzer automatisch auf, alle gefährlichen Berechtigungen für die App bei der Installation zu erteilen.

Wenn der Benutzer zustimmt, werden alle von der App angeforderten Berechtigungen gewährt. Wenn der Benutzer die Berechtigungsanfrage ablehnt, bricht das System die Installation der App ab. Wenn durch ein App Update zusätzliche Berechtigungen erforderlich werden, wird der Benutzer aufgefordert, diese neuen Berechtigungen zu akzeptieren, bevor die Aktualisierung ausgeführt wird.

2. Die Berechtigung für den Internet-Zugriff unserer App einholen

Nachdem wir im vorherigen Abschnitt das App Permissions System von Android näher kennengelernt haben, werden wir nun im praktischen Teil dieser Lektion die Berechtigung für den Internet-Zugriff unserer App einholen. Wie wir erfahren haben, muss jede Android App die von ihr benötigten Berechtigungen im App Manifest deklarieren.

Hinweis: Falls es der eigene App erlaubt sein soll Netzwerkdaten als Klartext zu senden und zu empfangen, muss seit Android 9.0 (API Level 28) ihrem Attribut android:usesCleartextTraffic der Wert true zugewiesen werden. Standardmäßig ist es auf false gesetzt, wodurch Klartext-HTTP (cleartext HTTP) anwendungsweit unterbunden wird.

Die notwendige Änderung werden wir nun ausführen und im App Manifest die für den Internet-Zugriff benötigte Berechtigung bekanntgeben. Wir öffnen daher die AndroidManifest.xml Datei im Editorfenster von Android Studio durch einen Doppelklick auf die entsprechende Datei im Project Tool Window. Die Datei befindet sich im Ordner app/src/main/ unseres Projekts.

Wir geben nun in der AndroidManifest.xml Datei die benötigte Berechtigung bekannt. Dazu fügen wir die markierte Zeile in die Manifest-Datei ein:

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="de.codeyourapp.zitate">

    <!-- Diese Genehmigung wird für das Öffnen von Network Sockets benötigt. -->
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>

Im oberen Code ist der Inhalt der AndroidManifest.xml Datei angegeben. In Zeile 5 wird die für den Internet-Zugriff benötigte Berechtigung bekanntgegeben. Dazu wird die Berechtigung mit Hilfe eines <uses-permission> Elements im App Manifest deklariert. Dabei muss das <uses-permission> Element ein Kindelement des top-level <manifest> Elements sein.

Welche Berechtigung die Android App benötigt, wird durch das Attribut android:name bekanntgegeben. In unserem Fall ist es die android.permission.INTERNET Berechtigung, die unsere Anwendung für das Öffnen von Network Sockets benötigt. Weitere Berechtigungen werden von unserer App nicht benötigt. Wären jedoch zusätzlichen Berechtigungen erforderlich, müssten diese mit weiteren <uses-permission> Elementen an dieser Stelle deklariert werden.

Das Verhalten des Android Systems nach dem Deklarieren einer Berechtigung hängt davon ab, wie sensibel die Berechtigung ist. In unserem Fall handelt es sich bei der Internet-Berechtigung um eine normale Berechtigung, die das Android System sofort bei der Installation der App gewährt. Würde es sich um eine gefährliche Berechtigung handeln, müsste der Nutzer später zur Laufzeit explizit die Zustimmung zur angeforderten Berechtigung erteilen.

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

android_manifest_permission

Im App Manifest ist die benötigte Berechtigung, der Zugriff auf das Internet, bekanntgegeben worden

Durch das Deklarieren der Berechtigung android.permission.INTERNET (Markierung A) ist unserer Android App jetzt in der Lage auf das Internet zuzugreifen. Unserer Anwendung kann nun mit Hilfe von HTTP-Anfragen echte online Daten von einem Webserver anfordern.

3. Implementieren der HTTP-Anfrage in der Utility-Klasse

Da unsere Android App jetzt die Berechtigung besitzt, auf das Internet zugreifen zu dürfen, können wir mit dem Implementieren der HTTP-Anfrage beginnen. Unsere Anwendung wird die HTTP-Anfrage nutzen, um neue Zitate bei unserem Webserver anzufragen. Der Zugriff auf die Serverdaten wird mittels einer Anfrage-URL erfolgen, deren Aufbau wir weiter unten ausführlich beschreiben werden.

Die HTTP-Anfrage werden wir mit Hilfe einer neuen Klasse, der Utility-Klasse, realisieren. Die neue Klasse ist als Hilfsklasse konzipiert und wird sich hauptsächlich um Aufgaben kümmern, die direkt mit dem HTTP-Request zu tun haben.

Bevor wir die Utility-Klasse in Android Studio anlegen werden, möchten wir nun die Anfrage-URL vorstellen, mit der unsere App die Zitate beim Webserver anfragen wird.

3.1 Aufbau der URL mit der die HTTP-Anfrage durchgeführt wird

Eine URL (Uniform Resource Locator) verweist auf eine beliebige Ressource im Internet (World Wide Web). Die Ressource kann eine Datei, ein Verzeichnis oder auch ein komplexes Objekt, wie eine Datenbank-Suchanfrage, sein.

In unserem Fall führt die URL zu einer PHP-Datei auf unserem Webserver. Die PHP-Datei wertet die Parameter der Anfrage aus und generiert daraufhin die angeforderte Anzahl zufälliger Zitate im JSON– oder XML-Format generiert.

Mit folgender Anfrage-URL lassen wir 5 zufällige Zitate im JSON-Format von dem Webserver erzeugen:

https://www.codeyourapp.de/tools/query.php?count=5&mode=0

Die oben aufgeführte URL besteht aus vier Teilen. Sie beginnt mit dem Schema https://, durch welches das zu verwendende Protokoll (Hypertext Transfer Protocol Secure) vorgegeben wird. Danach steht der Host Computer www.codeyourapp.de auf dem sich die Daten befinden.

Anschließend folgt der Pfad, der zu den Serverdaten führt. Dieser lautet /tools/query.php?count=5&mode=0 und enthält den Abfrage-String (Query String). Der Query String wird mit einem Fragezeichen eingeleitet und enthält Parameter-Werte-Paare (Key-Value Pairs), die mit einem kaufmännischen &-Zeichen voneinander getrennt sind.

Unser Query String besteht aus den beiden Parameter count und mode. Mit dem Parameter count wird vorgegeben, wie viele zufällige Zitate der Webserver generieren soll. Der Parameter mode legt fest, in welchem Format die Zitatdaten vorliegen sollen. Es stehen JSON und XML als Formate für die vom Webserver generierten Zitatdaten zur Auswahl.

Die vom Webserver erzeugte Antwort kann direkt im Browser betrachtet werden. Dazu muss nur die oben angegebene Anfrage-URL, die zu den Serverdaten führt, angeklickt werden.

Als Ergebnis erhält man folgende Browserausgabe:

anfrage_http_url

Der Webserver liefert zufällige Zitate im JSON-Format zurück

Die Antwort des Webservers auf die Anfrage-URL https://www.codeyourapp.de/tools/query.php?count=5&mode=0 ist in der oberen Abbildung dargestellt. Sie enthält die generierten Zitatdaten, welche im JSON-Format erzeugt wurden. Neben den Zitatdaten sind in der Serverantwort auch Diagnoseinformationen enthalten.

Welche Informationen die Serverantwort im Detail enthält und wie das JSON-Format zu interpretieren ist, werden wir in der nächsten Lektion ausführlich beschreiben, wenn wir die vom Server erhaltenen Daten von unserer Android App auswerten und weiterverarbeiten lassen. In dieser Lektion werden wir unseren Fokus hauptsächlich auf die HTTP-Anfrage selbst richten, mit deren Hilfe die Zitatdaten angefordert werden.

Da wir nun die Anfrage-URL näher kennengelernt habe, können wir uns nun dem HTTP-Request zuwenden und die Utility-Klasse implementieren, welche für das Durchführen der HTTP-Anfrage verantwortlich sein wird.

3.2 Erstellen der Utility-Klasse

Wir werden nun die Java Klasse Utility unserem Android Studio Projekt hinzufügen. Sie wird für das Durchführen der HTTP-Anfrage, also für das Anfordern neuer Zitate von unserem Webserver, verantwortlich sein.

Um die Hilfsklasse Utility anzulegen, muss eine neue Java Klassendatei in dem Package-Ordner des Projekts erstellt werden. Dafür gibt es zwei Vorgehensweisen: über die obere Menüleiste oder über den Package-Ordner in der Project-Ansicht. Wir werden den zweiten Weg wählen, da er intuitiver und weniger fehleranfällig ist.

Als Erstes muss dafür die Project-Ansicht exakt so wie in Lektion 4 Abschnitt 2 beschrieben aufgeklappt werden. In diesen Package-Ordner werden wir nun die neu Klassendatei mit Hilfe des Create New Class-Dialog von Android Studio anlegen lassen.

Die Klassendatei Utility.java, unserer Hilfsklasse, 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.
utility_klasse_erzeugen

Erstellen der Utility-Klasse 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 Utility 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.
utility_klasse_benennen

Den Namen für die Utility-Klasse 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 Utility.java im Editorfenster von Android Studio mit einem Doppelklick auf den entsprechenden Eintrag in der linken Project-Ansicht.

Anschließend ersetzen wir ihren 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 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.

Die Utility-Klasse besteht aus vier Konstanten und zwei statischen Methoden. Ihre Aufgabe ist das Herstellen der Verbindung zum Webserver, Anfordern der Zitatdaten und Umwandeln der Daten in eine Zeichenkette, die später von unserer Anwendung weiterverarbeitet werden kann.

Die vier Konstanten werden in den Zeilen 17 bis 22 definiert. Die Konstante TAG wird für das Ausgeben von kurzen Log-Meldungen verwendet. Die Konstanten JSON_PARSING_METHOD und XML_PARSING_METHOD benötigen wir später für das Weiterverarbeiten der erhaltenen Zitatdaten, um zu entscheiden welche Auslesemethode verwendet werden soll.

Am wichtigsten ist die Konstante URL, die den statischen Teil der Anfrage-URL enthält. Dieser besteht aus dem Schema https:// welches das Protokoll festlegt, dem Host Computer auf dem sich die Daten befinden www.codeyourapp.de und dem Pfad zu den Daten /tools/query.php? inklusive Fragezeichen.

In den Zeilen 24 bis 60 wird die Methode requestQuotesFromServer() definiert. Sie kann von außerhalb aufgerufen werden und ist für das Anfordern der Zitatdaten vom Webserver verantwortlich. Als Rückgabewert liefert sie eine Zeichenkette, welche die Zitatdaten enthält, an den Aufrufer zurück.

In den Zeilen 62 bis 82 wird die Methode convertStreamToString() definiert. Sie ist eine Hilfsmethode, die nur innerhalb der Utility-Klasse aufgerufen werden kann, und ist für das Umwandeln des Datenstroms in eine Zeichenkette verantwortlich.

Wir werden nun die beiden eben genannten Methode genauer betrachten und dazu ihren Quellcode jeweils noch einmal aufführen.

Die requestQuotesFromServer() Methode

Wie bereits weiter oben erwähnt, wird in den Zeilen 24 bis 60 der Utility-Klasse die requestQuotesFromServer() Methode definiert. Ihre Aufgabe ist das Anfordern der Zitatdaten vom Webserver. Wie dies erfolgt, werden wir nun beschreiben. Die Methode ist daher zur Übersichtlichkeit an dieser Stelle nochmals aufgeführt:

public static String requestQuotesFromServer(int quotesCount, int parsingMethod) {

    // Zusammenbauen der Anfrage-URL
    String requestUrl = URL + "count=" + quotesCount + "&mode=" + parsingMethod;
    Log.i(TAG, requestUrl);

    String quotesString = null;
    HttpURLConnection httpURLConnection = null;
    try {

        // Aufbauen der Verbindung zum Webserver - Timeout nach 9000ms
        URL url = new URL(requestUrl);
        httpURLConnection = (HttpURLConnection) url.openConnection();
        httpURLConnection.setRequestMethod("GET");
        httpURLConnection.setConnectTimeout(9000);
        httpURLConnection.setReadTimeout(9000);

        // Anfordern der Daten und Umwandeln dieser in eine Zeichenkette (String)
        InputStream stream = new BufferedInputStream(httpURLConnection.getInputStream());
        quotesString = convertStreamToString(stream);

    } catch (MalformedURLException e) {
        Log.e(TAG, "MalformedURLException: " + e.getMessage());
    } catch (ProtocolException e) {
        Log.e(TAG, "ProtocolException: " + e.getMessage());
    } catch (IOException e) {
        Log.e(TAG, "IOException: " + e.getMessage());
    } catch (Exception e) {
        Log.e(TAG, "Exception: " + e.getMessage());
    } finally {
        if (httpURLConnection != null) {
            httpURLConnection.disconnect();
        }
    }

    return quotesString;
}

Die Methode requestQuotesFromServer() besitzt die beiden Parameter quotesCount und parsingMethod, über die vorgegeben wird, wie viele Zitate vom Webserver generiert werden und welches Format die Daten besitzen sollen. Die beiden Parameter werden in Zeile 4 für den Zusammenbau der Anfrage-URL verwendet.

Anschließend wird im try-Block in den Zeilen 9 bis 22 eine Verbindung zum Webserver aufgebaut und die Zitatdaten als Datenstrom angefordert. Der vom Server erhaltene InputStream wird an die convertStreamToString() Methode übergeben, die ihn in eine Zeichenkette umwandelt. Die zurückerhaltene Zeichenkette wird in der Variable quotesString abgelegt.

Abschließend erfolgt die Ausnahmenbehandlung mit vier catch-Blöcken, mit deren Hilfe mögliche Exceptions abgefangen und kurze Fehlermeldungen an die Konsole ausgegeben werden. Im finally-Block wird schließlich die Verbindung zum Webserver wieder getrennt.

Bevor die Methode verlassen wird, werden in Zeile 36 die Zitatdaten, welche in der Variable quotesString abgelegt wurden, an den Aufrufer zurückgeliefert. In unserem Fall, wie wir weiter unten sehen werden, ist der Aufrufer die doInBackground() Methode unseres asynchronen Tasks.

Die convertStreamToString() Methode

Die convertStreamToString() Methode wird in den Zeilen 62 bis 82 der Utility-Klasse definiert. Ihre Aufgabe ist das Umwandeln des Datenstroms in eine Zeichenkette. Wie dies erfolgt, werden wir nun beschreiben. Die Methode ist daher zur Übersichtlichkeit an dieser Stelle nochmals aufgeführt:

private static String convertStreamToString(InputStream is) {
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
    StringBuilder stringBuilder = new StringBuilder();

    String line;
    try {
        while ((line = bufferedReader.readLine()) != null) {
            stringBuilder.append(line).append('\n');
        }
    } catch (IOException e) {
        Log.e(TAG, "IOException: " + e.getMessage());
    } finally {
        try {
            bufferedReader.close();
        } catch (IOException e) {
            Log.e(TAG, "IOException: " + e.getMessage());
        }
    }

    return stringBuilder.toString();
}

Die Methode convertStreamToString() besitzt den Parameter is vom Typ InputStream. Dieser enthält den vom Webserver erhaltenen Datenstrom mit den Zitatdaten. Die Aufgabe der convertStreamToString() Methode ist es, diesen Datenstrom in einen String umzuwandeln.

Dazu verwendet sie einen BufferedReader, mit dessen Hilfe der InputStream zeilenweise ausgelesen wird. An das Ende jeder ausgelesenen Zeile wird ein Zeilenumbruch angefügt. Diese Aufgabe wird von einem StringBuilder übernommen. Sobald alle Zeilen ausgelesen wurden, erfolgt der Zusammenbau der Zeichenkette mit dem Aufruf der toString() Methode auf dem StringBuilder-Objekt.

Die so erzeugte Zeichenkette wird an den Aufrufer, die requestQuotesFromServer() Methode zurückgeliefert. Sie enthält die von Webserver generierten Zitatdaten. In welchem Format diese Daten vorliegen, JSON oder XML, wird zu diesem Zeitpunkt noch nicht betrachtet. Dies wird später erfolgen, wenn wir die Utility-Klasse um zusätzliche Methoden erweitern.

In Android Studio sollte die Utility.java Klassendatei 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 Utility.java Klassendatei dargestellt. Ihre wichtigsten Bestandteile sind mit Markierungsrahmen versehen worden. Welche Bedeutung der jeweilige Code-Block besitzt, ist in der unteren Liste angegeben:

  1. A – Die Konstanten der Klasse. Die Konstante URL enthält den statischen Teile der Anfrage-URL.
  2. B – Die requestQuotesFromServer() Methode fordert die Zitatdaten vom Webserver.
  3. C – Die convertStreamToString() Methode wandelt den Datenstrom in eine Zeichenkette um.

Es muss unbedingt darauf geachtet werden, dass sich die neue Klasse in dem Package-Ordner de.codeyourapp.zitate befindet. Zur Kontrolle kann auf den oberen Projektstruktur-Reiter geklickt werden, um die aktuelle Struktur unseres Android Projekts anzuzeigen.

Da wir jetzt die Hilfsklasse Utility erstellt haben, können wir als Nächstes die HTTP-Anfrage von unserer App durchführen lassen. Dazu ist nur noch eine kleine Änderung an der MainActivity-Klasse vorzunehmen.

4. Starten der HTTP-Anfrage in der MainActivity-Klasse

In den vorherigen beiden Abschnitten haben wir die Berechtigung für den Internetzugriff unserer App beantragt und die Utility Hilfsklasse erstellt. Unsere Anwendung ist somit in der Lage eine HTTP-Anfrage zu stellen und dadurch Daten über das Internet von einem Webserver anzufordern.

Die HTTP-Anfrage werden wir von dem asynchronen Task durchführen lassen, welchen wir in der vorherigen Lektion implementiert haben. Dadurch ist sichergestellt, dass der UI-Thread nicht von der Anfrage blockiert, sondern diese in einem eigenen Hintergrund-Thread abgearbeitet wird.

Um die notwendige Änderung am asynchronen Task vorzunehmen, müssen wir die innere Klasse RequestQuotesTask der MainActivity-Klasse überarbeiten. 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 sind die Änderungen an der inneren Klasse RequestQuotesTask der MainActivity.java Datei bereits durchgeführt 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 wurde nur eine kleine Erweiterung an der inneren Klassen RequestQuotesTask vorgenommen. Und zwar wurden die Zeilen 196 bis 205 in die doInBackground() Methode direkt über der return-Anweisung eingefügt.

In Zeile 196 wird die HTTP-Anfrage gestartet. Dazu wird die statische Methode requestQuotesFromServer() über die Hilfsklasse Utility aufgerufen. Beim Aufruf werden ihr die beiden Argumente quotesCount und parsingMethod übergeben, mit welchen die Anzahl der zu generierenden Zitate und das Datenformat vorgeben werden. Der Rückgabewert, die Zeichenkette mit den vom Webserver generierten Zitatdaten, wird in der Variable quotesString gespeichert.

In den Zeilen 198 bis 205 lassen wir den Inhalt der quotesString Variable, also die erhaltenen Zitatdaten, in der Konsole als Log-Meldung ausgeben. Auf diese Weise können wir direkt in Android Studio im Logcat Tool Window prüfen, ob die Zitatdaten korrekt generiert und übertragen wurden. Sollten keine Zitatdaten empfangen worden sein, geben wir in dem else-Zweig eine kurze Fehlermeldung an den Benutzer in Form eines Toasts aus.

Außer dem Einfügen dieser Zeilen in die doInBackground() Methode des asynchronen Tasks müssen keine weiteren Änderungen an der MainActivity– bzw. RequestQuotesTask-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. Es ist nur die Methode aufgeklappt, an der Veränderungen vorgenommen wurden. Der Quellcode wurde nur in der doInBackground() Methode der inneren RequestQuotesTask-Klasse überarbeitet und zwar so, dass der asynchrone Task jetzt eine HTTP-Anfrage durchführt.

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 simuliert daraufhin eine kurze Ladezeit und startet anschließend die HTTP-Anfrage.

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

5. Ausführen und Testen unserer Android App

Wir werden nun unsere Android App auf einem Android Virtual Device im Emulator ausführen lassen und mit einer Swipe-Down Geste die HTTP-Anfrage vom asynchronen Task durchführen. Die dabei erzeugten Log-Meldungen werden wir im Logcat Tool Window von Android Studio betrachten und prüfen, ob die Zitatdaten korrekt angefordert und empfangen wurden.

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 (Zugriff auf das Internet) 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 klicken auf den Action-Button in der App Bar. Dadurch wird die refreshListView() Methode aufgerufen, von welcher der asynchrone Task gestartet wird. Daraufhin simuliert der asynchrone Task eine kurze Ladezeit und startet anschließend die HTTP-Anfrage.

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. Erst durch die komplette Neuinstallation der App wird die angeforderte Berechtigung (Zugriff auf das Internet) vom Android System korrekt erteilt. Die Antwort des Webservers sollte nun im Logcat Tool Window, wie unten dargestellt, ausgegeben werden.

Dafür wird zuerst der Anfrage-String zusammengesetzt und anschließend daraus ein URL-Objekt erzeugt, über das eine HttpURLConnection aufgebaut wird. Als Ergebnis erhalten wir die angefragten Zitatdaten von unserem Webserver zurück in Form eines JSON-Strings.

Bei diesem 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_antwort_text

Die Anfrage-URL und erhaltenen 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 Antwort erhalten. Wie zu erkennen ist, hat die Utility-Klasse die Anfrage-URL (Markierung A) korrekt erstellt.

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

Auf dem Display des Android Geräts bekommen wir die übermittelten Zitatdaten noch nicht angezeigt. Diese Funktion werden wir erst in der nächsten Lektion implementieren, wenn wir den JSON-String parsen (auslesen) und die darin enthaltenen Zitatinformationen auf dem Display in Form von ListView-Einträgen ausgeben.

Zusammenfassung

In dieser Lektion haben wir mit unserer Android App auf einen Webserver zugegriffen. Dazu haben wir an Server eine HTTP-Anfrage gestellt. Als Antwort haben wir daraufhin vom Webserver echte online Daten in Form einer Zeichenkette erhalten, welche die Daten von mehreren Zitat-Objekte im JSON-Format enthält.

Um sicherzustellen, dass der UI-Thread nicht von der Anfrage blockiert wird und somit die Benutzeroberfläche unserer Anwendung stets flüssig bedienbar bleibt, haben wir die Anfrage vom asynchronen Task durchführen lassen, den wir in der vorherigen Lektion implementiert hatten.

Bevor wir mit dem Implementieren der HTTP-Anfrage begonnen haben, betrachteten wir im theoretischen Teil dieser Lektion welche Bedingungen von unserer App für das Ausführen eines HTTP-Requests erfüllt werden mussten. Dabei haben wir auch die Sicherheitsarchitektur des Android Systems mit seinen unterschiedlichen Berechtigungen näher kennenlernen.

Anschließend haben wir im praktischen Teil dieser Lektion die Genehmigung für die HTTP-Anfrage für unsere App eingeholt und die Serveranfrage in einer eigenen Klasse, der Utility-Klasse, implementiert. Danach haben wir die HTTP-Anfrage von dem asynchronen Task in der MainActivity-Klasse durchführen lassen, wodurch sichergestellt wurde, dass der UI-Thread nicht von der Anfrage blockiert, sondern diese in einem eigenen Hintergrund-Thread abgearbeitet wird.

Abschließend haben wir unsere Android App im Emulator auf einem Android Virtual Device ausgeführt und eine HTTP-Anfrage an den Webserver gestellt. Die vom Server generierte Antwort haben wir dann im Logcat Tool Window von Android Studio analysiert und überprüft, ob die Daten korrekt übertragen wurden.

In der nächsten Lektion werden wir die erhaltenen Zitatdaten in unserer Android App weiterverarbeiten. Dazu werden wir aus der übermittelten Zeichenkette die im JSON-Format gespeicherten Zitatinformationen auslesen und daraus Quotes-Objekte erzeugen. Die so erzeugten Quotes-Objekte, werden wir dann als Einträge dem ListView unserer App hinzufügen.

Weiterführende Literatur




Comments 52

  1. Fehler: „Cleartext HTTP traffic not permitted“ bei Android 9

    Hallo Chris,

    super Kurs. Kleiner Hinweis zum Fehler
    „Cleartext HTTP traffic not permitted“

    Bei Android 9 musste ich folgende Zeile im Manifest unter
    <application zufügen:

    android:usesCleartextTraffic="true"

    Dann lief es

    Grüße und Dank

    1. Post
      Author

      Hallo Kurt,

      danke für dein Lob und den sehr wichtigen Hinweis. Ich hatte gar nicht mehr an die Einschränkung der HTTP-Kommunikation bei Android 9 gedacht. Ich werden den fehlenden Zusatz in der AndroidManifest.xml Datei ergänzen, so dass die App bei allen Lesern läuft.

      Nochmals vielen Dank für deinen Hinweis!

      Viele Grüße, Chris

    2. Moin
      ich bin durch Zufall nach auf deinen Komentar gestoßen nachdem ich mir bereits viele Youtube Videos zum Thema angeguckt habe und mit deinem Tipp läuft es jetzt endlich auch bei mir.

      Danke!

  2. Hallo, tolles Tutorial, keine Probleme soweit bis auf des hier. Erscheint sobald man auf „Aktualisieren“ drückt und die App schließt sich. Die Fehlermeldung verweist auf die Zeile:
    InputStream inputStream = httpURLConnection.getInputStream();

    Das ist die ganze Meldung:

    E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
        Process: de.programmierenlernen.aktiehq.app, PID: 15265
        java.lang.RuntimeException: An error occurred while executing doInBackground()
            at android.os.AsyncTask$3.done(AsyncTask.java:365)
            at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
            ...
         Caused by: java.lang.SecurityException: Permission denied (missing INTERNET permission?)
            at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:135)
            at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:90)
            ...
         Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
            at libcore.io.Linux.android_getaddrinfo(Native Method)
            at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:58)
            ...
         Caused by: android.system.ErrnoException: android_getaddrinfo failed: EACCES (Permission denied)
            at libcore.io.Linux.android_getaddrinfo(Native Method) 
            at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:58)
            ...
    Application terminated.
    

    Grüße

    1. Post
      Author

      Hallo Jonas,

      danke für’s Lob!

      Laut Fehlermeldung ist die Erlaubnis für den Internet-Zugriff nicht erteilt worden:

      Caused by: java.lang.SecurityException: Permission denied (missing INTERNET permission?)
      

      Hast du in der AndroidManifest.xml Datei den Zugriff auf das Internet, so wie in Abschnitt 2.2 beschrieben, erlaubt?

      <uses-permission android:name="android.permission.INTERNET" />
      

      Viele Grüße, Chris

  3. Der Service von yahoo funktioniert anscheinend nicht mehr, ich erhalte folgende Meldung bei den entsprechenden links:

    It has come to our attention that this service is being used in violation of the Yahoo Terms of Service. As such, the service is being discontinued. For all future markets and equities data research, please refer to finance.yahoo.com.

    1. Post
      Author

      Hallo Volker,

      Yahoo hat den Service eingestellt. Ich habe das Tutorial vor einiger Zeit überarbeitet, so dass nun simulierte Aktiendaten von meinem eigenen Webserver verwendet werden. Dadurch ist das Tutorial unabhängig von externen Diensten geworden.

      Viele Grüße, Chris

  4. Hallo Chris,

    vielen Dank für Dein super Tutorial. Es ist das Beste, das ich kenne.

    Nur schade, dass Yahoo die Möglichkeit des Datendownloads nun wohl seit 1. November 2017 nicht mehr anbietet. Beim Anklicken des Testlinks kommt auf jeden Fall die Meldung:
    “ … It has come to our attention that this service is being used in violation of the Yahoo Terms of Service. As such, the service is being discontinued. For all future markets and equities data research, please refer to finance.yahoo.com. …“

    Nun funktionieren einige wichtige Features der App leider nicht mehr.

    Viele Grüße

    1. Post
      Author

      Hallo Gunter,

      danke für dein Lob!

      Es stimmt. Yahoo hat den Service eingestellt. Ich habe das Tutorial vor einiger Zeit überarbeitet, so dass nun simulierte Aktiendaten von meinem eigenen Webserver verwendet werden. Dadurch ist das Tutorial unabhängig von externen Diensten geworden.

      Jetzt funktionieren die Funktionen der App wieder wie im Tutorial beschrieben.

      Viele Grüße, Chris

  5. Hi Chris,
    vielen Dank für das schöne Tutorial,

    ich interessiere mich auf für die APP Entwicklung und würde gerne ein eigene App programmieren.

    Wie finde ich denn alle notwendigen Funktionen die ich für die App benötige und welche Webseiten mir die notwendigen Daten zur Verfügung stellen um eine gute und nützliche App programmieren zu können?

  6. Hallo,
    mir ist aufgefallen das Yahoo! den Dienst nicht mehr zur Verfügung stellt und mich würde es freuen wenn jemand eine Lösung dafür bereitstellen würde.

    MfG Jonas

    1. Post
      Author

      Hallo Jonas,

      Es stimmt. Yahoo hat den Service eingestellt. Ich habe das Tutorial vor einiger Zeit überarbeitet, so dass nun simulierte Aktiendaten von meinem eigenen Webserver verwendet werden. Dadurch ist das Tutorial unabhängig von externen Diensten geworden.

      Jetzt funktionieren die Funktionen der App wieder wie im Tutorial beschrieben.

      Viele Grüße, Chris

    1. Post
      Author

      Hallo Bernd,

      Es stimmt. Yahoo hat den Service eingestellt. Ich habe das Tutorial vor einiger Zeit überarbeitet, so dass nun simulierte Aktiendaten von meinem eigenen Webserver verwendet werden. Dadurch ist das Tutorial unabhängig von externen Diensten geworden.

      Jetzt funktionieren die Funktionen der App wieder wie im Tutorial beschrieben.

      Viele Grüße, Chris

  7. Danke und ein Lob für die verständliche Einführung in die Android Programmierung. Mein Problem ist, das YQL keine csv – Daten mit Umlauten akzeptiert, ansonten ist die Umformungsidee top. Eventuell darf ich mir einen eigenen xml webservice bauen damit es genauso funktioniert.

  8. Hallo Chris,

    Bei mir sind folgende Meldungen im Terminal angezeigt:

    int logctl_get(): open '/dev/hwlog_switch' fail -1, 13. Permission denied
    
    Note: log switch off, only log_main and log_events will have logs!
    --------- beginning of main
    04-24 12:04:17.477 11554 11554 I AktienlisteFragment: information - Meldung
    04-24 12:04:17.477 11554 11554 W AktienlisteFragment: warning     - Meldung
    04-24 12:04:17.477 11554 11554 E AktienlisteFragment: error       - Meldung
    

    Alle Log-Meldungen ab Stufe verbose sind nicht ausgegeben worden.
    Was kann der Fehler sein?
    Freundliche Grüße
    Jan

  9. Hi,
    Habe ein Projekt vor weis aber nicht genau wie ich meinen Quellcode schreiben soll. Können Sie mir helfen?

    1. Post
      Author

      Hallo Andreas,

      wenn du möchtest, kannst du mir per E-Mail dein Projekt grob umschreiben. Eventuell kann ich dir ein paar Tipps geben. Die E-Mail Adresse kannst Du im Impressum finden.

      Viele Grüße, Chris

  10. Hi Chris,

    erstmal vielen Dank für deine Tutorialreihe. Ich bekomme wohl bei

    InputStream inputStream = httpURLConnection.getInputStream();

    einen Fehler. Ich weiß nicht wie ich weiter vorgehen soll, es handelt sich um einen Verbindungsfehler (Connection timed out).

    Hoffentlich kannst du mir weiterhelfen.

    Habe dir eine Mail geschickt mit den Projektdaten.

    1. Post
      Author

      Hallo Waldemar,

      deine Mail habe ich erhalten. Ich werde mal schauen, ob ich den Fehler finden kann.

      Viele Grüße, Chris

    2. Hast du den Fehler schon finden können? Ich komme einfach nicht weiter:(

    3. Post
      Author

      Hallo Waldemar,

      sorry das ich nicht schneller helfen kann. In letzer Zeit komme ich kaum dazu Lesern zu helfen. Ich habe mir dein Projekt schon angesehen, aber noch einen Konflikt mit meiner Android Studio Installation (ich benutze eine zu alte Version und muss daher noch updaten). Bis Sonntag sollte ich mit etwas Glück den Fehler gefunden haben. Ich geb dir dann über den Status Bescheid.

      Viele Grüße, Chris

  11. Hallo Chris,

    ich habe heute diesen Teil des Tutorial durchgearbeitet und entsprechend im Dokument angepasst.
    Bei mir werden allerdings, wenn ich in der App aktualisiere (Punkt 4.1 nach dem 1.Bild) weiterhin die Mock-Daten angezeigt. In der Konsole kommen, wie von die gesagt, die entsprechenden Daten rein.

    Soll das in diesem Stadium der Entwicklung so sein, oder liegt evtl ein Fehler in meinem Quelltext vor?

    Lg
    Stormy

    1. ok, gerade selber herausgefunden…
      In der nächsten Lektion Abschnitt 2 der letzte Satz:
      „Im nächsten Abschnitt werden wir den XML-String parsen (auslesen) und die erhaltenen Finanzinformationen auf dem Display ausgeben.“
      Diese Information wäre wirklich hilfreich gewesen, damit man weiß das man alles richtig gemacht hat.

    2. Post
      Author

      Hallo Stormy,

      danke für den Hinweis. Ich habe die relevanten Stellen in Teil 8 entsprechend überarbeitet, so dass es jetzt hoffentlich klarer für die Leser ist.

      Viele Grüße, Chris

  12. Hallo Chris,
    ich bekomme seit dem 3.Teil jedesmal wenn ich in der App „Aktualisiere“ eine Fehlermeldung über einen unbekannten Buffer. Als ich heute Morgen weiter machen wollte, (Ich habe AS und den Emulator frisch gestartet) hat sich das Problem anscheinend exponentiell erweitert, da ich inzwischen mehrere Meldungen bekomme:

    09-22 07:36:05.094 2737-2815/de.programmierenlernenhq.aktiehq.app E/Surface: getSlotFromBufferLocked: unknown buffer: 0x7f4a13c627a0
    09-22 07:36:06.685 2737-2815/de.programmierenlernenhq.aktiehq.app E/Surface: getSlotFromBufferLocked: unknown buffer: 0x7f4a13c61f50
    09-22 07:36:09.213 2737-2815/de.programmierenlernenhq.aktiehq.app E/Surface: getSlotFromBufferLocked: unknown buffer: 0x7f4a13c61000
    

    Irgendwelche Ideen woran das liegen könnte?
    App funktioniert bisher genauso wie sie funktionieren soll, das ist nicht das Problem, aber es macht mich stutzig das die ganze Zeit ein bufferproblem herscht und jetzt mehrere.

    Lg Stormy

    1. Post
      Author

      Hallo Stormy,

      OK, eine solche Fehlermeldung habe ich selbst noch nicht erhalten. Wenn du möchtest kann ich mal dein Android Projekt bei mir laufen lassen und schauen, ob das Problem auch auf meinem System auftritt. Ich würde dafür die Projektdateien als Zip per E-Mail benötigen. Die E-Mail Adresse steht im Impressum.

      Haben eventuell andere Leser auch eine solche Fehlermeldung angezeigt bekommen?

      Viele Grüße, Chris

    2. Post
      Author

      Hallo Stormy,

      das Problem mit dem unbekannten Buffer tritt bei Android 6.0 (Marshmallow) auf. In der Version Android 6.0.1 sollte dieser Fehler behoben worden sein, wobei ich da meine Zweifel habe.

      Zu dem Thema habe ich folgende interessante Links finden können:

      StackOverflow: Unknown Buffer
      StackOverflow: Unknown Buffer in Marshmallow
      Google Code: Unknown Buffor Issue

      Auf meinem Entwicklungsgerät Samsung S4 Mini tritt der Unknown Buffer Error nicht auf. Dort läuft aber auch Android 4. Auf dem Android Virtual Device im Emulator trat der Fehler auf. Dort habe ich Android 6.0 laufen.

      Viele Grüße, Chris

  13. Hi Chris,
    ich hätte da mal eine Frage:
    Die XML-Datei, die ich in meiner App auslesen möchte wird durch eine .htaccess-Datei mit Benutzernamen und Passwort geschützt. Ich besitze die Zugangsdaten und kann die Datei auch über den Browser aufrufen. Aber wie mache ich das nun in Android Studio? Ich habe es schon nach dem Muster

    URL url = new URL(„http://benutzername:passwort@domain.de/abc/datei.xml“)

    probiert, was ebenfalls im Browser funktioniert. In Android Studio wirft das aber eine FileNotFoundException.

    Grüße
    Sebastian

    1. Post
      Author
  14. Hallo zusammen,

    danke für das tolle Tutorial, sehr aufschlussreich. Jetzt bin ich allerdings an einer Stelle wo ich mir nicht mehr ganz sicher bin. Ich habe alles von oben durchgeführt, allerdings verändern sich die Daten auf dem UI nicht nachdem ich die App abspiele, woran liegt es? Bzw. welche Informationen benötigt Ihr, um mir zu sagen woran es liegt?

    Gruß
    Viktor

    1. Post
      Author

      Hallo Viktor,

      schwer zu sagen, woran es liegt. Wenn Du möchtest, kannst Du mir Deine Projektdateien (den ganzen Android Studio Projektordner) als ZIP per E-Mail zusenden. Die E-Mail Adresse kannst Du im Impressum finden. Ich schaue dann mal, ob ich den Fehler finden kann.

      Viele Grüße, Chris

  15. Guten Abend Chris,

    da ich wahrscheinlich dasselbe Problem habe wie Paul, wäre es hilfreich,
    wenn die dortige Lösung gleich allgemein veröffentlicht würde.

    Gruß
    joe

    1. Post
      Author

      Hallo Joe,

      bei Paul lag es an dem „uses-permission“-Tag in der AndroidManifest.xml Datei. Dieser Tag war nicht in der obersten Ebene angegeben.

      Viele Grüße, Chris

    2. Hallo,

      ich habe das selbe Problem, an dem AndroidManifest.xml liegt es allerdings nicht. Hier ist alles so wie im Tutorial.

      Bei mir erscheint folgender Logtext:

      W/InputEventReceiver: Attempted to finish an input event but the input event receiver has already been disposed.
      V/RenderScript: Application requested CPU execution
      V/RenderScript: 0xaec0ca00 Launching thread(s), CPUs 4
      E/HoleDatenTask: Error 
                       java.io.FileNotFoundException: https://query.yahooapis.com/v1/public/yql?
      q=select%20*%20from%20csv%20where%20
      url='http://download.finance.yahoo.com/d/quotes.csv?
      s=BMW.DE%26f=snc4xl1d1t1c1p2ohgv%26e=.csv'%20and%20
      columns='symbol,name,currency,exchange,price,date,time,change,
      percent,open,high,low,volume'&amp;diagnostics=true
      

      Habe gerade nur BMW.DE drin, aber daran wird es ja nicht liegen.

      Vielen Dank schonmal für die Hilfe 🙂

      Gruß Benny

    3. Post
      Author

      Hallo Benny,

      an BMW.DE liegt es, wie du schon sagst, nicht. Wenn du möchtest, kannst Du mir deine Projektdateien (den ganzen Android Studio Projektordner, aber OHNE die build-Unterordner) als ZIP per E-Mail zusenden. Die E-Mail Adresse kannst Du im Impressum finden. Ich schaue dann mal, ob ich etwas herausfinden kann.

      Viele Grüße, Chris

  16. Die Seiten gefallen mir echt gut. Das Toutorial habe ich bis Teil 8 durchgearbeitet.
    Leider stürzt das Programm bei Zeile 51 ab. (InputStream inputStream = httpURLConnection.getInputStream();)

    Das Programm geht auch nicht in den Catch Block.
    Woran liegt das?
    den Inhalt von httpURLConnection steht hier:

    libcore.net.http.HttpsURLConnectionImpl$HttpUrlConnectionDelegate:
    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
    
    1. Post
      Author

      Hallo Paul,

      hmmm, schwierig zu sagen warum es abstürzt ohne Quellcode.

      Wenn Du möchtest, kannst Du mir Deine Projektdateien als ZIP per E-Mail zusenden. Ich werde dann mal drüber schauen, vielleicht kann ich den Fehler finden. Die E-Mail Adresse kannst Du im Impressum finden.

      Viele Grüße, Chris

  17. Hi Chris,

    mir ist gerade die nette Überschrift zum 4. Abschnitt aufgefallen – ob Yahoo-Finance wirklich Wetterdaten preis gibt? Da musste ich doch schmunzeln. War dies hier mal ein Wetterdaten-Projekt? Wo kann man denn Wetterdaten herunter laden?

    Gruß, Reinhard

    1. Post
      Author

      Hallo Reinhard,

      danke für den Hinweis. Ich habe den Fehler eben korrigiert.

      Ja, früher war das Android Tutorial ein Wetterdaten-Projekt. Die App hieß WetterHQ und war eine einfache Wetter-App. Die Wetterdaten hatten wir damals von http://openweathermap.org/ über deren API abgefragt.

      Viele Grüße, Chris

  18. Leider wird seit diesem Abschnitt meine App immer angehalten sobald ich auf aktualisieren drücke. Habe mich sehr viel damit beschäftigt zu versuchen den Fehler zu finden.
    Leider ohne erfolg.
    Wurde mich sehr interessieren was ich falsch gemacht habe.
    Vieleicht hast du ja eine idee.
    Hatte auch erstmal weiter gemacht.

    Vielen dank

    1. Post
      Author

      Hallo Mark,

      schwer zu sagen ohne Quellcode. Es könnte ein Tippfehler in Deinem Quellcode sein. Tippfehler schleichen sich schnell ein. Wenn Du möchtest, kannst Du mir Deine Projektdateien als ZIP per E-Mail zusenden. Ich werde dann mal drüber schauen, vielleicht kann ich den Fehler finden. Die E-Mail Adresse kannst Du im Impressum nachschauen.

      Viele Grüße, Chris

  19. hi,
    habe die Anfrage genau so ausprobiert, funktioniert leider nicht. Habe mir die neue URL selbst zusammen gebaut:

    https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20csv%20where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com
    %2Fd%2Fquotes.csv%3Fs%3DBMW.DE%2CDAI.DE%26f%3Dsnc4xl1d1t1c1p2ohgv%26e%3D.csv'
    %20and%20columns%3D'symbol%2Cname%2Ccurrency%2Cexchange%2Cprice%2Cdate
    %2Ctime%2Cchange%2Cpercent%2Copen%2Chigh%2Clow%2Cvolume'
    &amp;format=xml&amp;env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys
    

    mit der kriege ich raten im browser und in der app, aber was mit parsen funktioniert jetzt nicht mehr richtig, Daten werden auf dem device nicht mehr richtig angezeigt.
    Was ist zu tun?

    1. Post
      Author

      Hallo Soraya,

      schwer zu sagen ohne Quellcode. Wenn du möchtest, kannst du mir deine Projektdateien per E-Mail zusenden. Ich werde dann mal drüber schauen, vielleicht kann ich den Fehler finden. Die E-Mail Adresse kannst du im Impressum nachschauen.

      Viele Grüße, Chris

    2. Wie würdest du denn die neue url parsen?
      Denn ich glaube die alte ist einfach nicht mehr aktuell und ich habe dass mit dem parsen noch nicht so verstanden.

    3. Post
      Author

      Hallo Soraya,

      die URL aus dem Tutorial ist aktuell. Ich habe die URL gestern getestet, bevor ich auf deinen Kommentar geantwortet habe. Auch in der App funktioniert die URL so wie im Beitrag beschrieben. Daher vermute ich den Fehler in deinem Quellcode.

      Viele Grüße, Chris

    4. Wenn ich die URL aus dem gelben Kommentar in den Browser eingebe bekomme ich eine error Meldung zurück.

      Wenn du sagst dass sie aktuell ist, wie benutze ich sie dann richtig?

    5. Post
      Author
  20. Pingback: Android Tutorial: XML Daten auslesen und anzeigen in Android

  21. Pingback: Android Tutorial: Hintergrundberechnungen mit AsyncTask

Schreibe einen Kommentar

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