![]() |
Die Artists-App im Android Emulator |
Änderungen am Layout
Da wir das Projekt mit dem Standard-Template angelegt
hatten, sollte es eine Layout-Datei namens activity_main.xml in unserem
res/layout-Verzeichnis geben. Den Inhalt des TextView-Tags ändern wir in dieser Datei geringfügig: Es wird nicht mehr 'Hello Word', sondern ein anfangs leerer Text
angezeigt. Ausserdem bekommt die View eine ID, über die wir sie später mit Daten
bestücken:
<TextView
android:id="@+id/band"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />
Zum Service passende Bibliotheken?
Nach dem Android-Projekt, hatten wir ein zugehöriges
Backend-Projekt erzeugt. Das hatte zur Folge, dass der Wizard verschiedene Demo-Klassen zum Android-Projekt hinzugefügt hat. Außerdem sehen wir im
Android-Projekt noch Pakete, deren Namen mit dem Präfix endpoint-libs anfangen:
Damit Services genutzt werden können, müssen die zugehörigen Datentypen
auch am Client, also der Android App, bekannt sein. Wir hatten aber alle
generierten Services am Server gelöscht und durch eigene ersetzt. Die Bibliotheken am
Client repräsentieren also noch den initialen Zustand und sind nicht mehr
aktuell.
Altlasten bereinigen
Es ist ganz einfach den Client an den neuen Service
anzupassen. Rechtsklick auf das Artists-AppEngine Projekt, im Menüpunkt
'Google' den Punkt 'Generate Cloud Endpoint Client Library' wählen und alles passt wieder. Im
Android-Projekt gibt es jetzt bei den Endpoint-Bibliotheken den Ordner bandsservice-v1-generated-source,
der die Klassen BandsService und Band enthält, die uns bekannt vorkommen
sollten.
Im Android-Projekt tauchen nun Fehlermeldungen auf: Zwei
der 'alten' Klassen finden benötigte Typen nicht mehr in den endpoint-libs.
Kein Problem! Wir brauchen die beiden Klassen GCMIntentService und
RegisterActivity nicht mehr und löschen sie. Lediglich CloudEndpointUtils wird
uns - wie der Name schon sagt - noch nützlich sein. Diese Klasse enthält beispielsweise
auch Methoden, die die Verbindung zum Server herstellen. Da wir zunächst mit einem lokal Server arbeiten, ändern wir die Konstante LOCAL_ANDROID_RUN auf den Wert true.
Die Activitiy initialisieren
Um unsere Service-API zu nutzen, müssen wir die Klasse MainActivity
anpassen:
public class MainActivity extends Activity {
private BandsService
endpoint = null;
private TextView
bandTV;
@Override
protected void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bandTV=(TextView)
findViewById(R.id.band);
BandsService.Builder endpointBuilder = new BandsService.Builder(
AndroidHttp.newCompatibleTransport(), new JacksonFactory(),
new
HttpRequestInitializer() {
public void
initialize(HttpRequest httpRequest) {
}
});
endpoint =
CloudEndpointUtils.updateBuilder(endpointBuilder).build();
...
Die ersten Zeilen der onCreate-Methode führen die gewohnten
Initialisierungsarbeiten durch. Bei der Initialisierung der Variablen
endPointBuilder handelt es sich um einfachen Boilerplate Code, um den Builder unseres
Services zu erzeugen. Echte Funktionalität wird nicht hinzugefügt. In der
letzten Zeile wird dann das Attribut endpoint zum Proxy für unsere
serverseitige API gemacht.
Asynchroner Netzwerkzugriff
Bis jetzt hat sich die App noch nicht mit dem Netzwerk verbunden. Es
wäre auch nicht wünschenswert gewesen. Seit Android 3 ist nämlich der
Strict-Mode standardmäßig aktiviert. Dieser sorgt dafür, dass die App Exceptions
wirft, sobald der GUI-Thread der App Ein- oder Ausgaben über Speichermedien oder Netzwerke durchführt. Das soll dafür
sorgen, dass Entwickler solche Aufgaben in eigene Threads auslagern und so ein
bessere User Experience ohne wartende GUI-Threads bieten.
Es gibt jetzt verschiedene Möglichkeiten zur asynchronen Programmierung
unter Android, die Arbeit mit der Klasse AsyncTask bietet viele Vorteile. Das Muster
sieht vor, dass man eine eigene private AyncTask-Klasse in der Activity
definiert:
private class
EndpointTask extends AsyncTask<Void, Void, Band> {
@Override
protected Band
doInBackground(Void... params) {
Band result =
null;
try {
result =
endpoint.bandsAPI().getBand(0).execute();
} catch
(IOException e) {
e.printStackTrace();
}
return result;
}
protected void
onPostExecute(Band band) {
String text =
band.getName()+": "+ band.getFounded();
bandTV.setText(text);
}
}
Die Methode doInBackground startet automatisch einen neuen
Thread. Die Methode execute baut die
Verbindung zum Server auf, von dem dann mit getBand(0) die Daten, die zum Datensatz
mit der ID 0 gehören abgerufen werden. Wenn doInBackground und damit der Thread
beendet sind, wird onPostExecute im GUI-Thread abgearbeitet und die TextView
mit den ermittelten Daten versorgt.
Wir dürfen jetzt nicht vergessen die AsyncTask zu starten.
Die letzten beiden Zeilen in der onCreate Methode lauten:
...
new
EndpointTask().execute();
}
Fast fertig
Die App macht jetzt das was sie soll. Naja, fast: Der Server
läuft immer noch lokal auf unserer Entwicklungsmaschine und die Daten sind
nicht persistiert, sondern werden in einem Array gehalten. Diese beiden Defizite werden in den folgenden Artikeln beseitigt werden.
Keine Kommentare:
Kommentar veröffentlichen