Android Tutorial Http Web Services und mehr (mit Lybraries arbeiten)

klaus

Expert
Licensed User
Currency Converter / Währungswandler

Dieses Tutorial verwendet folgendes Web Service in einem Programm für Währungskonvertierung:

http://www.webservicex.net/CurrencyC...ToCurrency=EUR


Um das Beste aus diesem Tutorial zu machen ist es vorteilhaft den kompletten Code des Beispielprogrammes herunter zu laden. Er befindet sich am Ende.
Das Englische Originaltutorial.



cc1.png


Es gibt mehrere wichtige Aspekte in dieser Anwendung.

Dieses Tutorial wird jedes Thema nur kurz berühren.

Files / Dateien
Man kann Dateien in das Projekt im Tab (unten recht im IDE) zufügen:


cc_files.png


In unserem Fall haben wir zwei Dateien. CountryCodes.txt ist eine Textdatei mit der Liste der Währungen. Jede Zeile enthält genau einen Wert.

layout1.bal ist die Layout-Datei die mit dem Designer erstellt wurde. Layout-Dateien werden automatisch in den Datei-Manager hinzugefügt.
Es ist zu beachten daß die Layout-Datei noch zwei Bilddateien, die Tasten Pfeile, enthält. Diese Dateien sind im Designer angezeigt. Wenn wir layout1.bal entfernen werden diese Dateien auch aus dem Projekt entfernt.

Die gepackten Dateien (Projekdateien) sind auch Assets benannt. Lokal sind sie im Files Unterordner gespeichert.

Dieser Code liest die Textdatei und speichert die Daten in einer Liste:
B4X:
    If FirstTime Then
        countries = File.ReadList(File.DirAssets, "CountryCodes.txt")
File.ReadList ist eine praktische Methode, die eine Datei öffnet und alle Zeilen in eine List einfügt. Dateien sind immer durch ihren Ordner und Namen definiert.
Die Assets sind mit in der vordefinierten Variable File.DirAssets referenziert.
Das Android-Dateisystem unterscheidet Groß- und Kleinschreibung. Was bedeutet, daß image1.jpg und Image1.jpg nicht gleich sind (im Gegensatz zum Windows-Dateisystem).

Structures / Strukturen

Man kann neue Types oder Strukturen mit dem Schlüßelwort Typedefinieren. Später kann man Variablen dieses neuen Types deklarieren.
Type kann beliebige andere Objekte enthalten, einschließlich anderer Types und auch sich selbst (einschließlich auch Arrays von allen diesen Types).
Structures werden tiefer in einem anderen Tutorial erklärt.
Structures müssen in einer der beiden globalen Subs deklariert, Sub Globals oder Sub Process_Globals.
B4X:
Type MyTag (FromValue As EditText, ToValue As EditText, _
                 FromCurrency As Spinner, ToCurrency As Spinner)
    Dim CurrentTask As MyTag
Dieser Code deklariert einen Type der zwei EditTexts (Textfelder) und zwei Spinner (Comboboxes) enthält.
Wir deklarieren auch eine Variable dieses Types, mit dem Namen
[FONT=&quot] CurrentTask[/FONT].
Im Code sieht man auch daß wir einen anderen Type namens
[FONT=&quot]StateType[/FONT] haben in den wir die Daten des aktuellen Zustandes speichern.

Alle Views haben eine Eigenschaft (property) namens
Tag. Man kann diese Eigenschaft auf ein beliebiges Objekt stellen.
Wir werden es gemeinsam mit dem
Sender Schlüßelwort verwenden um beide Buttons in der gleichen Subroutine zu behandeln.


Libraries / Bibliotheken

cc_libs.png


Wie man im Bild sieht, zeigt der Libraries Tab eine Liste der verfügbaren Bibliotheken an. Die angehakten Bibliotheken sind in das Projekt eingebunden. Achtung, man kann die Core Bibliothek nicht 'löschen' denn sie ist ja der Kern von Basic4Android !



Adding additional libraries / Zusätzliche Bibliotheken zufügen


Eine Bibliothek besteht aus einem Dateien-Paar. Eine xml-Datei, die die Bibliothek beschreibt und eine jar-Datei, die den kompilierten Code enthält.

Weitere Bibliotheken und Updates zu offiziellen Bibliotheken sind hier verfügbar: http://www.basic4ppc.com/forum/addit...icial-updates/
Achtung: nur Benutzer die Basic4Android gekauft haben (registirerte Benutzer) können zusätzliche Bibliotheken herunterladen.
Zum anfügen von zusätzlichen Bibliotheken braucht man nur das Dateien-Paar in einen von Basic4Android bekannten Ordner zu kopieren.
Standardmäßig ist dies der "Libraries"-Ordner der sich normalerweise : C:\Program Files\AnywhereSoftware\Basic4android\Libraries ist.
Man kann auch einen anderen Ordner für die zusätzlichen Bibliotheken erstellen, man muß diesen dann aber in Basic4Android konfigurieren unter Tools - Configure Paths.
Zu beachten ist, daß der Ordner für zusätzliche Bibliotheken als erster Ordner für vorhandene Bibliotheken durchgesucht wird. Das bedeutet, daß man eine vorhandene Originalbibliothek updaten kann indem man die neue Version einfach in den Ordner für zusätzliche Bibliotheken kopiert (es ist dann nicht nötig die alten Dateien im internen Ordner von Basic4Android zu löschen).


Http library / Http Bibliothek

Die Http Bibliothek enthält drei Objekte.
HttpClient- Dies ist das Hauptobjekt, das die Anfragen (requests) und Antworten (responses) verwaltet. [FONT=&quot]HttpClient[/FONT] kann mehrere Anfragen (requests) gleichzeitig ausführen.
Es ist sehr wichtig, HttpClient als Prozess global zu erklären. HttpClient behandelt Anfragen im Hintergrund und es darf nicht an die Lebenszeit der Activity gebunden sein.
Eine Kommunikation wird in zwei Stufen durchgeführt. Zuerst wird eine Verbindung erstellt durch Senden eines HttpRequest Objektes und dann wird die Antwort vom Server gelesen.
Der erste Schritt ist immer ein nicht blockierender Vorgang. Es kann lange dauern bis die Verbindung hergestellt ist und man möchte ja nicht daß während dieser Zeit das Programm nicht mehr reagiert. Android hat eine spezielle DialogBox "Programm reagiert nicht" (Application not responding), die dem Benutzer erlaubt Android zu zwingen daß die Anwendung geschlossen wird.

Die zweite Stufe, das Behandeln der Antwort, kann entweder blockierend oder nicht blockierend sein. Wenn man zum Beispiel eine Datei herunterladen will sollten man vorzüglicherweise die nicht blockierende Option wählen.

Dieser Code erstellt und sendet eine GET Anfrage (request).
B4X:
Dim request As HttpRequest
    request.InitializeGet(URL & fromCountry & "&ToCurrency=" & toCountry)
    request.Timeout = 10000 'set timeout to 10 seconds
    If HttpClient1.Execute(request, 1) = False Then Return 'Will be false if their is already a running task (with the same id).
Wir setzen das Timeout auf 10 Sekunden was sehr kurz ist. Der Standardwert ist 30 Sekunden. Das Ziel Web-Service ist sehr instabil, was die Dinge noch interessanter macht. Ich bevorzuge es aber, in unserem Fall, schnell scheitern zu lassen.

Die HttpClient.Execute Methode erhält zwei Parameter. Der erste ist das Request-Objekt und der zweite ist die Task-ID. Diese Integer Zahl wird in den ResponseSuccess oder ResponseError Events zurück gegeben.
Sie erlaubt Ihnen, zwischen verschiedenen Tasks zu unterscheiden, die im Hintergrund laufen können.
HttpClient.Executegibt False zurück, falls bereits ein Task mit dem gleichen ID läuft. Dies hilft mehrere unnötige Anfragen zu vermeiden.
Sie können auch den Status der laufenden Prozesse mit dem Schlüßelwort IsBackgroundTaskRunningüberprüfen.
Sobald die Antwort bereit ist, wird ResponseSuccess oder ResponseError getriggert. Wenn Alles gut ging, können wir jetzt die Antwort lesen, finden die Geschwindigkeit und zeigt sie an. Ansonsten zeigen wir eine "Toast"-Nachricht mit der Fehlermeldung.

Wie oben schon angedeutet, scheint dieser spezifische Web-Service instabil zu sein, und Ihre Erfahrungen dürften unterschiedlich sein.


State / Zustand

Wie schon im Activities Lebensdauer Tutorial beschrieben, sind wir verpflichtet, den Zustand der Anwendung zu speichern und wieder herzustellen. In unserem Fall sind die Zustandparameter die Werte in den Textboxen und die aktuellen gewählten Währungen.


Der folgende Type und Variable sind in der Sub Process_GlobalsRoutine deklariert:
B4X:
   Type StateType (TextUp As String, TextDown As String, _
        IndexUp As Int, IndexDown As Int)
    Dim State As StateType 'This must be a process variable as it stores the state
                            'and should not be released when the activity is destroyed.
Beim ersten Durchlauf setzt man die Werte auf die Standardwerte die man braucht:
B4X:
Sub ResetState
    'set the starting state
    State.TextUp = 1
    State.TextDown = ""
    State.IndexUp = 0 'USD
    State.IndexDown = 43 'Euro
End Sub
Später speichern wir sie und lesen sie nach Bedarf wieder ein:
B4X:
Sub Activity_Resume
    txtUp.Text = State.TextUp
    txtDown.Text = State.TextDown
    spnrUp.SelectedIndex = State.IndexUp
    spnrDown.SelectedIndex = State.IndexDown
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    If UserClosed Then
        ResetState 'reset the state to the initial settings.
    Else
        State.TextUp = txtUp.Text
        State.TextDown = txtDown.Text
        State.IndexUp = spnrUp.SelectedIndex
        state.IndexDown = spnrDown.SelectedIndex
    End If
End Sub
In Activity_Resume lesen wir die Werte und setzten sie in die relevanten Views ein. Zu beachten ist daß Activity_Resume direkt nach Activity_Create aufgerufen wird. Das heißt daß sie auch beim ersten Durchlauf des Programmes aufgerufen wird.

In Activity_Pause speichern wir die Werte in das Zustand Objekt (das eine Prozess Variable ist).
Wenn der Benutzer auf die Back Taste drückt (was bedeutet, daß er die Anwendung schließen will) geben wir den originalen Zustand zurück. Daher wird der Benutzer eine "neue saubere" Anwendung finden, wenn er die Anwendung das nächste Mal aufruft.

Dieser Zeile sollte man besondere Aufmerksamkeit schenken:
B4X:
CurrentTask.FromCurrency.SelectedItem.SubString2(0, 3)
CurrentTask ist ein MyTag Type.
Es hat ein Feld mit dem namen FromCurrency das ein Spinner Objekt
ist.
Spinner hat eine Eigenschaft (property) von Namen SelectedItem die einen String zurück gibt.
String hat eine Methode (Funktion) von Namen Substring2.

Dieser Code ist auch gültig: "abcd".Substring(2)


Das komplette Projekt mit Sourcecode findet man am Ende:

B4X:
'Activity module
Sub Process_Globals
    Dim countries As List
    Dim URL As String
    URL = "http://www.webservicex.net/CurrencyConvertor.asmx/ConversionRate?FromCurrency="
    Dim HttpClient1 As HttpClient
    Type StateType (TextUp As String, TextDown As String, _
        IndexUp As Int, IndexDown As Int)
    Dim State As StateType 'This must be a process variable as it stores the state
                            'and should not be released when the activity is destroyed.
End Sub

Sub Globals
    Dim txtUp, txtDown As EditText
    Dim spnrUp, spnrDown As Spinner
    Dim btnUp, btnDown As Button
    Type MyTag (FromValue As EditText, ToValue As EditText, _
                 FromCurrency As Spinner, ToCurrency As Spinner)
    Dim CurrentTask As MyTag
End Sub
Sub ResetState
    'set the starting state
    State.TextUp = 1
    State.TextDown = ""
    State.IndexUp = 0 'USD
    State.IndexDown = 43 'Euro
End Sub

Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then
        Log("************************")
        'load the list of countries
        countries = File.ReadList(File.DirAssets, "CountryCodes.txt")
        'initialize the HttpClient object which is responsible for all communication.
        HttpClient1.Initialize("HttpClient1")
        ResetState
    End If
    
    Activity.LoadLayout("layout1")
    spnrUp.AddAll(countries)
    spnrDown.AddAll(countries)
    
    Dim t1 As MyTag
    t1.FromValue = txtUp
    t1.ToValue = txtDown
    t1.FromCurrency = spnrUp
    t1.ToCurrency = spnrDown
    btnDown.Tag = t1
    
    Dim t2 As MyTag
    t2.FromValue = txtDown
    t2.ToValue = txtUp
    t2.FromCurrency = spnrDown
    t2.ToCurrency = spnrUp
    btnUp.Tag = t2
End Sub

Sub Activity_Resume
    txtUp.Text = State.TextUp
    txtDown.Text = State.TextDown
    spnrUp.SelectedIndex = State.IndexUp
    spnrDown.SelectedIndex = State.IndexDown
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    If UserClosed Then
        ResetState 'reset the state to the initial settings.
    Else
        State.TextUp = txtUp.Text
        State.TextDown = txtDown.Text
        State.IndexUp = spnrUp.SelectedIndex
        state.IndexDown = spnrDown.SelectedIndex
    End If
End Sub
Sub btn_Click
    Dim btn As Button
    btn = Sender 'Fetch the actual button that raised this event.
    CurrentTask = btn.Tag 'Take the object from its Tag property.
    Dim fromCountry, toCountry As String
    fromCountry = CurrentTask.FromCurrency.SelectedItem.SubString2(0, 3) 'get the currency code
    toCountry = CurrentTask.ToCurrency.SelectedItem.SubString2(0, 3)
    
    Dim request As HttpRequest
    request.InitializeGet(URL & fromCountry & "&ToCurrency=" & toCountry)
    request.Timeout = 10000 'set timeout to 10 seconds
    If HttpClient1.Execute(request, 1) = False Then Return 'Will be false if their is already a running task (with the same id).
    ProgressDialogShow("Calling server...")
End Sub
Sub HttpClient1_ResponseSuccess (Response As HttpResponse, TaskId As Int)
    Log("ResponseSuccess")
    ProgressDialogHide
    Dim result As String
    result = Response.GetString("UTF8") 'Convert the response to a string
    Log(result)
    Dim rate As Double
    'Parse the result
    i = result.IndexOf(".NET/")
    If i = -1 Then
        Msgbox("Invalid response.", "Error")
        Return
    End If
    i2 = result.IndexOf2("<", i + 1)
    rate = result.substring2(i + 7, i2)
    Log("Rate = " & rate)
    If IsNumber(CurrentTask.FromValue.Text) = False Then
        Msgbox("Please enter a valid number.", "Error")
        Return
    End If
    'Set the answer
    
    CurrentTask.ToValue.Text = Round2(CurrentTask.FromValue.Text * rate, 2)
End Sub
Sub HttpClient1_ResponseError (Reason As String, StatusCode As Int, TaskId As Int)
    Log(Reason)
    Log(StatusCode)
    ProgressDialogHide
    msg = "Error connecting to server."
    If reason <> Null Then msg = msg & CRLF & Reason
    ToastMessageShow (msg, True)
End Sub

Das Programm:

zip.gif
CurrencyConverter.zip
 
Last edited:
Top