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.
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:
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:
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.
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="] CurrentTask[/FONT].
Im Code sieht man auch daß wir einen anderen Type namens [FONT="]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
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.b4x.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="]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).
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:
Beim ersten Durchlauf setzt man die Werte auf die Standardwerte die man braucht:
Später speichern wir sie und lesen sie nach Bedarf wieder ein:
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:
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:
Das Programm:
CurrencyConverter.zip
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.
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:
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")
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
Wir deklarieren auch eine Variable dieses Types, mit dem Namen[FONT="] CurrentTask[/FONT].
Im Code sieht man auch daß wir einen anderen Type namens [FONT="]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
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.b4x.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="]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).
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.
B4X:
Sub ResetState
'set the starting state
State.TextUp = 1
State.TextDown = ""
State.IndexUp = 0 'USD
State.IndexDown = 43 'Euro
End Sub
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_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)
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:
Last edited: