Entwicklung einer auf Scalabasierenden Android-Applikation fürdas...

108
Masterarbeit Entwicklung einer auf Scala basierenden Android-Applikation für das Hochschul-Informationssystem Spirit der Fakultät Informatik an der Fachhochschule Schmalkalden Zur Erlangung des akademischen Grades eines Master of Science - Media Processing and Interactive Services - Fakultät Informatik Referent: Prof. Dr. Oliver Braun Korreferent: Dipl.-Mathematiker Michael Otto eingereicht von: Sebastian Stallenberger Matr.-Nr. 230534 Neuhauser Str. 5 97616 Bad Neustadt Schmalkalden, den 20.09.2011

Transcript of Entwicklung einer auf Scalabasierenden Android-Applikation fürdas...

Page 1: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Masterarbeit

Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Zur Erlangung des akademischen Grades einesMaster of Science- Media Processing and Interactive Services -

Fakultät InformatikReferent: Prof. Dr. Oliver BraunKorreferent: Dipl.-Mathematiker Michael Otto

eingereicht von:Sebastian StallenbergerMatr.-Nr. 230534Neuhauser Str. 597616 Bad Neustadt

Schmalkalden, den 20.09.2011

Page 2: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Danksagung

Zu Beginn bedanke ich mich bei meinen Eltern, die mich immer bei all meinenVorhaben unterstützt haben und sehr geduldig mit mir und meinem langen Studiumwaren. Ich danke Prof. Dr. Oliver Braun, der mich in der Zeit, in der diese Arbeitentstanden ist, sehr gut betreut hat und mir zu jeder Zeit als Ansprechpartner zurVerfügung stand.Weiterhin danke ich dem Team von Spirit, insbesondere Benjamin Lüdicke, Ron-ny Schleicher und Florian Schuhmann für die exzellente Zusammenarbeit und dievielen interessanten und teilweise hitzigen Diskussionen. Mein weiterer Dank fürUnterstützung geht an Tobias Gießler und Vanessa Brech.Abschließend danke ich auch den Autoren diverser Software-Projekte, mit denenich per E-Mail Kontakt hatte und die mich bei Problemen beratend unterstützten.Dazu zählen: Jan Berkel (android-plugin), Coda Hale (Jerkson) und Carsten EltonSørensen (Treeshaker).

Page 3: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Inhaltsverzeichnis

1 Einleitung 11.1 Spirit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.3 Ziel der Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.4 Vorgehensweise der Arbeit . . . . . . . . . . . . . . . . . . . . . . . . 31.5 Versionsfestlegung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2 Vorstellung der Technologien 52.1 Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.1.1 Geschichte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.1.2 Architektur . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.1.3 Market . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.1.4 Android SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2.2 Scala . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

3 Entwicklungsumgebungen 143.1 Vorbereitungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143.2 Konsole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.3 Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.4 IntelliJ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173.5 Wahl für die Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

4 Anforderungsanalyse 194.1 Erforderliche Features . . . . . . . . . . . . . . . . . . . . . . . . . . 194.2 Optionale Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

5 Entwurf 215.1 MainActivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225.2 NewsMulti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235.3 NewsSingle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245.4 NewsCreate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255.5 TimeTable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265.6 TimeSlot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275.7 Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275.8 Entwürfe von Hintergrundprozessen . . . . . . . . . . . . . . . . . . . 29

5.8.1 News oder TimeTable abrufen . . . . . . . . . . . . . . . . . . 295.8.2 News oder Kommentar erstellen . . . . . . . . . . . . . . . . . 31

Sebastian StallenbergerIII

Page 4: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Inhaltsverzeichnis Fachhochschule Schmalkalden SS 2011

6 Prototypische Implementierung 326.1 Struktur der Applikation . . . . . . . . . . . . . . . . . . . . . . . . . 326.2 AsyncTasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326.3 Activity MainActivity . . . . . . . . . . . . . . . . . . . . . . . . . . 35

6.3.1 onCreate und onResume . . . . . . . . . . . . . . . . . . . . . 366.3.2 Passphrase-Eingabe für die Beta . . . . . . . . . . . . . . . . . 366.3.3 Hauptmenü . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396.3.4 Options menu . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

6.4 Activity NewsMulti . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446.4.1 Konstruktion der News-Liste . . . . . . . . . . . . . . . . . . . 456.4.2 Aufbau einer einzelnen News . . . . . . . . . . . . . . . . . . . 466.4.3 onActivityResult . . . . . . . . . . . . . . . . . . . . . . . . . 48

6.5 Activity NewsSingle . . . . . . . . . . . . . . . . . . . . . . . . . . . . 496.6 Activity NewsCreate . . . . . . . . . . . . . . . . . . . . . . . . . . . 536.7 Activity Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596.8 Activity Info . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 646.9 Toilers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

6.9.1 JsonProcessor . . . . . . . . . . . . . . . . . . . . . . . . . . . 666.9.2 SpiritHttpClient . . . . . . . . . . . . . . . . . . . . . . . . . . 686.9.3 SpiritConnect . . . . . . . . . . . . . . . . . . . . . . . . . . . 696.9.4 ViewBuilder . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716.9.5 SpiritHelpers . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

7 Distribution 76

8 Fazit 78

Literaturverzeichnis 80

A Anhang 83A.1 Tutorials für die Einrichtung von Entwicklungsumgebungen . . . . . . 83

A.1.1 Ergänzungen zur Einrichtung von SBT . . . . . . . . . . . . . 83A.1.2 Einrichtung von Umgebungsvariablen . . . . . . . . . . . . . . 83A.1.3 Konsole . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84A.1.4 Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84A.1.5 IntelliJ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85A.1.6 Manuelles Signieren anstatt ’prepare-market’ . . . . . . . . . . 87

A.2 Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88A.3 Icons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99

Eidesstattliche Erklärung 104

Sebastian StallenbergerIV

Page 5: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

1 EinleitungSmartphones sind aus der heutigen Welt nicht mehr wegzudenken. Nachdem Applemit dem iPhone gezeigt hatte, dass Smartphones durchaus bei der breiten Masse An-klang finden, strömten schnell neue Konkurrenten auf den Markt. Android ist hier-bei das Betriebssystem für Smartphones mit der aktuell größten Verbreitung1. Einebislang kaum beachtete Nische ist die Programmierung von Android mit der objekt-funktionalen Sprache Scala. Diese Arbeit soll einen Überblick über die Entwicklungvon Android-Applikationen mit Scala bieten. Betrachtet wird die Entwicklung einerAndroid-Applikation für die Hochschul-Informationsplattform Spirit2.

1.1 SpiritSpirit ist ein junges Projekt der Fakultät Informatik an der Fachhochschule Schmal-kalden. Unter der Leitung von Prof. Dr. Oliver Braun hat man es sich zum Zielgemacht, den Informationsfluss zwischen der Fakultät, den Lehrenden und den Stu-denten zu optimieren.Um dieses Vorhaben in die Tat umzusetzen, wurde das Projekt in Teilbereichemit folgenden Aufgaben unterteilt: Stundenpläne müssen vor Beginn des Semes-ters erzeugt, validiert und verteilt werden. Ein reibungsloser Übergang vom aktu-ellen Stundenplan-System auf die Spirit-Variante muss möglich sein. Dies erfordertzusätzlich, dass die bisherigen Stundenplan-Daten in das neue System migriert wer-den können. Auch die verteilte Berechnung von Stundenplänen wird in einer Arbeituntersucht.Ein wichtiger Punkt des Projekts Spirit sind Service-Anwendungen für Lehrendeund Studierende. So ist es zum Einen ein Ziel, für die Lehrenden ein intuitives Ma-nagement ihrer Lehrveranstaltungen und Neuigkeiten zu schaffen. Zum Anderen willman den Studenten ermöglichen, schneller an Neuigkeiten heranzukommen und sichindividuelle Stundenpläne zusammenzustellen. Somit soll die Planung ihres Studi-ums deutlich vereinfacht werden. All dies wird durch die Entwicklung und Betreuungzweier unabhängiger Web-Plattformen realisiert. StudWeb ist hierbei das Angebotfür die Studenten, EmployeeWeb das für die Lehrenden.Geplant sind neben den über Browser erreichbaren Angeboten auch Applikationenfür mobile Endgeräte. Hierbei werden die Plattformen (Google) Android, MicrosoftWindows Phone 7 und Apple iOS berücksichtigt, um ein möglichst großes Areal desSmartphone-Marktes abzudecken.

1Laut [IDC11] lag der Marktanteil von Android am 9. Juni 2011 bei 38,9%.2Vgl. http://spirit.fh-schmalkalden.de

Sebastian Stallenberger Seite 1 von 104

Page 6: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

1. Einleitung Fachhochschule Schmalkalden SS 2011

Als Fundament zur Realisierung des Projekts Spirit gilt die funktionale Program-mierung. So wird versucht, wann immer es möglich ist, große Teile des Projekts infunktionalen Sprachen umzusetzen. Statt Java wird z.B. Scala oder Haskell einge-setzt und statt C# z.B. F#.Diese Arbeit wird sich mit der Entwicklung der Android-Applikation „SpiritMobile“in der funktionalen Programmiersprache Scala auseinandersetzen. SpiritMobile sollden einfachen Zugriff auf die diversen Services von Spirit ermöglichen. Hierbei wirdsich der Autor mit den dabei auftretenden Problemen und deren Lösungen befassen.Besonders der Implementierung soll dabei viel Aufmerksamkeit geschenkt werden.

1.2 MotivationDie offiziell von [Goo11c] für die Entwicklung von Applikationen für Android emp-fohlene und unterstützte Sprache ist Java3. Warum sollte man also eine alternativeProgrammiersprache wie Scala einsetzen?Nach Meinung des Autors ist diese Frage vom wissenschaftlichen Standpunkt ausbetrachtet falsch gestellt. So sollte man eher fragen: Warum sollte man eine alterna-tive Programmiersprache wie Scala nicht dazu nutzen, Applikationen für Androidzu entwickeln?Gründe dafür gibt es auf den ersten Blick zumindest theoretisch nicht. Laut [Bra11,S.1] kombiniert Scala als Hybrid-Sprache die Features von objektorientierten undfunktionalen Programmiersprachen. Die Programmierung sowohl mit Java als auchmit Scala liefert Java Bytecode, der auf dem Android Betriebssystem ausführbar ist.Zusätzlich „lässt sich auch jeglicher Java-Code direkt aus Scala heraus nutzen undumgekehrt“[Bra11, S.2].Dies macht Scala zu einer idealen alternativen Sprache für die Android Program-mierung. Im Kapitel 2.2 wird die Sprache Scala detaillierter betrachtet.

1.3 Ziel der ArbeitDas Ziel dieser Arbeit ist es, zu zeigen, wie Android Applikationen mit Hilfe vonScala entwickelt werden können. Dazu zählt unter anderem: Welche Entwicklungs-umgebungen sind geeignet? Treten Probleme dabei auf? Wie können diese gelöstwerden?Das Ziel dieser Arbeit ist auch der Entwurf und die prototypische Implementierungder Applikation SpiritMobile für Android. Dies soll anhand von Code-Auszügen ausder prototypischen Implementierung erläutert werden.

3Vgl. http://www.java.com

Sebastian Stallenberger Seite 2 von 104

Page 7: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

1. Einleitung Fachhochschule Schmalkalden SS 2011

1.4 Vorgehensweise der ArbeitNach der Einleitung werden die Erfahrungen des Autors mit aktuellen Entwicklungs-umgebungen in Bezug auf die Verwendbarkeit mit Android und Scala erläutert. Ineiner Anforderungsanalyse wird geklärt, welche Anforderungen sowohl von Seite derFachhochschule als auch von Seite des Autors an die Applikation SpiritMobile ge-stellt werden. Diese werden eingeteilt in die Kategorien erforderlich und optional.Der wichtigste Teil der Arbeit ist die Planung und die prototypische Implementie-rung des Android-Clients SpiritMobile für das Projekt Spirit.Am Ende der Arbeit erfolgt ein Fazit der gemachten Erfahrungen und ein Ausblickin die mögliche Zukunft von SpiritMobile. Auf die Schnittstellen, die zusammen mitanderen Teammitgliedern definiert wurden, wird in dieser Arbeit nicht eingegangen.Die in dieser Arbeit verwendeten Abbildungen sind nicht nach dem Standard UMLangefertigt worden, da dieser die Grafiken oft unnötig komplex machen würde undfür einige darzustellenden Elemente keine UML-Vertreter existieren.Die Sprache in den Abbildungen wechselt oft zwischen Deutsch und Englisch, wasdaher rührt, dass die original Namen der Elemente aus dem Datenmodell und derprototypischen Implementierung nicht eingedeutscht werden sollten. Dies schafft eineenge Verbindung zwischen den Abbildungen, dem Datenmodell und den praktischenAusführungen.Der Autor hat sich auch mit dem Testen in einer Android-Scala-Umgebung beschäf-tigt. Zum einen hat das Thema aber eine zu hohe Komplexität, um es nur kurzanzureißen. Zum anderen würde eine ausführliche Betrachtung vom Umfang her ei-ne eigene wissenschaftliche Arbeit füllen. Daher wird das Thema in dieser Arbeitnicht behandelt.

1.5 VersionsfestlegungBei der Festlegung der Android-Version wurde auf die Erhebung von [Goo11g] zu-rückgegriffen. Die folgenden Daten beziehen sich auf eine Periode von 14 Tagen, dieam 1. August 2011 endete. Wie in der Tabelle 1.1 zu sehen, nutzen über 80% aller

Plattform API Level VerteilungAndroid 1.5 3 1,3%Android 1.6 4 2,0%Android 2.1 7 15,2%Android 2.2 8 55,9%Android 2.3 - 2.3.2 9 0,6%Android 2.3.3 - 2.3.4 10 23,7%Android 3.0 11 0,4%Android 3.1 12 0,7%Android 3.2 13 0,2%

Tabelle 1.1: Verbreitung aktueller Android-Versionen in Anlehnung an [Goo11g]

Sebastian Stallenberger Seite 3 von 104

Page 8: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

1. Einleitung Fachhochschule Schmalkalden SS 2011

Android-Nutzer eine Version höher als oder gleich 2.2. Deshalb wurde die Android-Version, für die in dieser Arbeit entwickelt wird, auf 2.2 festgelegt.Im folgenden Kapitel werden die Basis-Technologien Android und Scala näher vor-gestellt.

Sebastian Stallenberger Seite 4 von 104

Page 9: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

2 Vorstellung der TechnologienIn diesem Kapitel werden die beiden großen Komponenten dieser Arbeit vorgestellt:Android und Scala.

2.1 AndroidLaut [Goo11j] ist Android eine Software-Sammlung für mobile Geräte, die ein Be-triebssystem, Middleware und Schlüssel-Applikationen umfasst. Das Android SDKstellt Werkzeuge und Schnittstellen bereit, die nötig sind, um mit Java für die An-droid Plattform zu entwickeln. Auf das Android SDK wird im Kapitel 2.1.4 nähereingegangen. Als großer Vorteil wird bei Android oft die Offenheit genannt, mit demes seinen Nutzern begegnet. Im Gegensatz zu Apple oder Microsoft lässt Google demNutzer zur Zeit einen relativ großen Freiraum und damit auch viel Kontrolle übersein Gerät. So kann ein Nutzer zum Beispiel apk-Pakete auf vielen Wegen auf seinGerät spielen und installieren.Laut [Goo11j] bringt Android unter anderem folgende Features mit sich:

• Applikations-Framework: Ermöglicht die Wiederverwendung und den Er-satz von Komponenten.

• Integrierter Browser: Basiert auf der Open-Source WebKit Engine.• Grafik-Unterstützung: Android bringt eine angepasste 2D-Grafik-Bibliothek

mit sich. 3D-Grafiken basieren auf der OpenGL ES 1.0 Spezifikation. Abhängigvon der Hardware wird auch Hardwarebeschleunigung unterstützt.

• SQLite: Ermöglicht das strukturierte Speichern von Daten.• Medien-Unterstützung: Gebräuchliche Datentypen für Audio(MP3, AAC,

AMR), Video(MPEG4, H.264) und Bilder(JPG, PNG, GIF) werden unter-stützt.

• Abhängig von der Hardware ist möglich:– GSM Telefonie– Aufbau von Verbindungen über Bluetooth, EDGE, 3G und WLAN– Nutzung vonKameras,GPS, einemKompass undBeschleunigungs-sensoren

Android kann nicht nur auf Smartphones sondern zielgerichtet angepasst auf vielenArten von Geräten eingesetzt werden. So ist geplant, Android auch z.B. in Au-tos, Spielekonsolen oder Set-Top-Boxen zum Einsatz zu bringen. Auf Millionen vonTablet-PCs, die derzeit den Markt erobern, läuft es bereits. [BP10, S.19]Im Folgenden geht der Autor auf wichtige Punkte in Bezug auf Android ein undbeginnt mit einem kurzen geschichtlichen Überblick.

Sebastian Stallenberger Seite 5 von 104

Page 10: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

2. Vorstellung der Technologien Fachhochschule Schmalkalden SS 2011

2.1.1 Geschichte

Ursprünglich wurde Android nicht von Google entwickelt. 2005 kaufte Google daskleine Unternehmen Android von Andy Rubin1, der vor der Entwicklung von An-droid unter anderem schon bei Apple Inc. gearbeitet hatte. Im November 2007 ver-kündete Google, gemeinsam mit anderen Mitgliedern der Open Handset Alliance2

ein Betriebssystem für Mobiltelefone zu entwickeln. Offiziell verfügbar ist Androidseit Oktober 2008 und seine Nutzerzahlen wachsen seitdem ungebremst. [Wik11]

2.1.2 Architektur

Abbildung 2.1 gibt einen Überblick über den Aufbau eines aktuellen Android-Systems.Die wichtigsten Bereiche werden in diesem Kapitel erläutert. Soweit nicht anders an-gegeben, gilt als Quelle für dieses Kapitel [Goo11j].

Abbildung 2.1: Die Android Achitektur in Anlehnung an [BP10, Abb. 2-1] und[Goo11j]

1Vgl. http://de.wikipedia.org/wiki/Andy_Rubin2Vgl. http://www.openhandsetalliance.com

Sebastian Stallenberger Seite 6 von 104

Page 11: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

2. Vorstellung der Technologien Fachhochschule Schmalkalden SS 2011

Linux-Kernel

Laut [BP10] ist die „Basis von Android [...] ein Linux-Kernel. Dieser enthält er-forderliche Gerätetreiber und besitzt einige Optimierungen, vor allem in Bezug aufEnergieverbrauch und Speichermanagement“. Derzeit wird ein Kernel der Version2.6 eingesetzt. Dieser wirkt auch als eine Abstraktionsschicht zwischen der Hardwa-re und der Android-Software-Sammlung.

Bibliotheken

Die Android Bibliotheken lassen sich einteilen in die Standard-Bibliotheken und dieAndroid-Laufzeitumgebung. Die Standard-Bibliotheken sind in C/C++ geschrie-ben. Sie ermöglichen die von Android-Anwendungen geforderten Funktionen wie z.B.Datenbankzugriff, 2D- und 3D-Grafiken, Webzugriff und Multimediaverwaltung.Zu diesen Bibliotheken zählen zum Beispiel:

• LibWebCore: Liefert eine auf WebKit basierendeWebbrowser-Umgebung. Web-Kit wird unter anderem auch in Google Chrome oder in iOS eingesetzt.

• SQLite: Stellt ein Datenbanksystem bereit, das sich im mobilen Bereich be-währt hat.

• Media Framework: Basierend auf dem quelloffenen Multimedia-Subsystem Open-CORE ist das Android Media Framework für die Darstellung und Verarbei-tung der verbreitetsten Multimedia-Formate zuständig. Die Grafikdarstellun-gen übernehmen die Bibliotheken SGL (2D) und OpenGL 1.0 (3D).

Zur Android-Laufzeitumgebung zählen die Android Laufzeitbibliotheken unddie Dalvik Virtual Machine (DVM). Für jede unter Android ausgeführte Anwen-dung wird ein eigener System-Prozess gestartet (Sandbox-Prinzip) und in diesemeine DVM. Die dadurch entstehenden Vorteile in Sachen Sicherheit und Verfügbar-keit relativieren den erhöhten Ressourcen-Verbrauch. Die DVM basiert laut [BP10]„auf der quelloffenen JVM3 Apache Harmony, wurde aber in Aufbau und Funkti-onsumfang an die Anforderungen mobiler Endgeräte angepasst“. Im Gegensatz zurklassischen JVM nutzt die DVM Register moderner Prozessoren. Wie in Abbildung

Abbildung 2.2: Der Weg vom Java- zum Dex-Bytecode in Anlehnung an [BP10]Abb. 2-2

3Java Virtual Machine

Sebastian Stallenberger Seite 7 von 104

Page 12: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

2. Vorstellung der Technologien Fachhochschule Schmalkalden SS 2011

2.2 zu sehen, werden die durch den javac erzeugten *.class-Dateien (Java-Bytecode)mit dem dx-Werkzeug in *.dex-Dateien (Dex-Bytecode) umgewandelt. Diese werdenanschließend in einem *.apk-Paket zu einer Anwendung zusammengefasst.

Framework

Der Android-Framework „stellt einige Systemklassen zur Verfügung, die den Zugriffauf Hardwarekomponenten aus der Anwendung heraus erlauben. [...] Viele dieserKlassen werden als Manager bezeichnet“[BP10]. Diese Klassen sind in Java geschrie-ben. Wichtige Manager sind laut [Goo11j] zum Beispiel:

• View System: Wird genutzt, um die grafische Oberfläche einer Applikationaufzubauen. Diese kann z.B. Listen, Grids, Buttons oder einen einbettbarenWebbrowser enthalten. Auf weitere grafische Elemente sowie die verschiedenenLayouts wird im Kapitel 6 eingegangen.

• Resource Manager: Stellt den Zugriff auf Ressourcen bereit, die nicht imCode definiert sind. Dies können z.B. Strings, Grafiken und Layout Dateiensein.

• Notification Manager: Ermöglicht den Applikationen, selbst definierte Nach-richten in der Status-Bar anzuzeigen.

• Activity Manager: Überwacht und kontrolliert den Lifecircle von Applika-tionen.

Neben den gerade vorgestellten Manager-Klassen können alle Android-Anwendungenvier Basis-Komponenten nutzen:

• Activity: Dienen Activities augenscheinlich zur Darstellung und Verwaltungvon Oberflächen, haben sie auch Aufgaben, die über die reine Darstellunghinausgehen. Beispiele für den Aufbau und die Verwendung von Activitiesfinden sich im Kapitel 6.

• Service: Operationen, die keine Oberfläche benötigen und im Hintergrundablaufen können/sollen, können in sogenannten Services realisiert werden.

• Content Provider: Sie dienen zur Abstraktion der unter einer Applikationliegenden Persistenzschicht. Darüber können Daten gespeichert und geladenwerden.

• Broadcast Reciever: Die sogenannten Broadcast Reciever sind verantwort-lich für die Kommunikation mit dem System. Sie empfangen Systemnachrich-ten wie z.B. über Störungen der Internetverbindung oder einen niedrigen Ak-kustand und reagieren darauf.

Anwendungsebene

Zur Anwendungsebene zählen sowohl Anwendungen, die von Google mitgeliefertwerden (Home-Screen, Telefonie, Browser, usw.), als auch selbstgeschriebene Anwen-dungen oder Anwendungen von Drittanbietern aus dem Market, der im folgendenAbschnitt genauer vorgestellt wird.

Sebastian Stallenberger Seite 8 von 104

Page 13: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

2. Vorstellung der Technologien Fachhochschule Schmalkalden SS 2011

2.1.3 Market

Der Android Market4 ist eine Plattform, über die Entwickler ihre Applikationen ver-treiben und Nutzer Applikationen kaufen und/oder downloaden können. Im Kapitel7 wird dieser detailliert vorgestellt, es werden Alternativen aufgezeigt und ebensodie Schritte zur Veröffentlichung einer Applikation erläutert.Um für den Market oder andere Vertriebsplattformen Anwendungen zu entwickeln,stellt Google das Android SDK bereit, welches im folgenden Abschnitt vorgestelltwird.

2.1.4 Android SDK

In diesem Abschnitt wird ein Überblick über die Komponenten des Android SDKgegeben. Die Abbildung 2.3 zeigt den jeweiligen Umfang der verschiedenen SDK-Versionen auf. Anschließend werden die wichtigsten Elemente erläutert.

Abbildung 2.3: Die verfügbaren SDK-Umgebungen im Versionsvergleich in Anleh-nung an [Goo11e]

4Vgl. https://market.android.com

Sebastian Stallenberger Seite 9 von 104

Page 14: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

2. Vorstellung der Technologien Fachhochschule Schmalkalden SS 2011

SDK Tools

Die SDK Tools beinhalten diverse Werkzeuge, die das Debuggen und Testen ei-ner Anwendung ermöglichen. Man findet diese im Unterverzeichnis tools des SDK.Folgend werden einige dieser Werkzeuge kurz vorgestellt. Soweit nicht anders ange-geben, gilt als Quelle für diesen Abschnitt [Goo11i].android: Ermöglicht die Verwaltung der Virtual-Devices (Erzeugen, Löschen, Be-trachten), der Android-Projekte (Erzeugen, Aktualisieren) und des SDK (Hinzufü-gen von Platforms, Add-ons und Dokumentation).ddms (Dalvik Debug Monitor Server): Ist ein Debugging-Tool. Es beinhaltet dieMöglichkeit,

• den Ressourcen-Verbrauch einzelner Prozesse einzusehen.• die Speicher-Belegung von Objekten zu tracken.• Dateien mit dem virtuellen oder angeschlossenen Device auszutauschen.• Informationen über laufende Threads zu bekommen.• Method-Profiling oder den LogCat zu nutzen.• Eigenschaften des Emulators zu verändern (z.B. den Verbindungsstatus oder

die Verbindungsgeschwindigkeit).• eingehende Anrufe oder SMS zu simulieren.• die Location des Device zu setzen.

Draw 9-patch: Ein WYSIWYG-Editor, um aus normalen Grafiken NinePatch-Grafiken zu erstellen. NinePatch-Grafiken zeichnen sich dadurch aus, dass eine Grö-ßenänderung verlustfreier durchgeführt werden kann, unter der Voraussetzung, mannutzt eine geeignete Grafik. Abbildung 2.4 zeigt die Aufteilung einer NinePatch-Grafik. Die Fläche A wird bei einer Größenänderung horizontal und vertikal ge-streckt. Für diesen Bereich ist eine einfarbige Fläche oder ein einfacher Verlauf zuempfehlen. Die Flächen B werden nur vertikal und die Flächen C nur horizontalgestreckt. Die Eck-Flächen D bleiben ungestreckt. Ideal ist diese Technik z.B. fürButtons.

Abbildung 2.4: Die Unterteilung einer NinePatch-Grafik in Anlehnung an [Dar10]

Sebastian Stallenberger Seite 10 von 104

Page 15: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

2. Vorstellung der Technologien Fachhochschule Schmalkalden SS 2011

emulator (Android Emulator): Ein auf QEMU5 basierender Emulator, auf dem einAndroid-System läuft und der zum Testen einer Applikation genutzt werden kann.Alle in dieser Arbeit enthaltenen Screenshots von SpiritMobile wurden mit diesemEmulator erstellt.hierarchyviewer (Hierarchy Viewer): Werkzeug mit grafischer Oberfläche zum De-buggen und Optimieren von GUIs6 in Android Applikationen. Die Abbildung 2.5zeigt den Hierarchy Viewer am Beispiel des Haupmenüs von SpiritMobile.

Abbildung 2.5: Der Hierarchy Viewer

Monkey & monkeyrunner: Monkey feuert im Emulator pseudo-zufällige „User-Events“ ab wie z.B. Klicks, Berührungen, Gesten oder System-Level-Events. Monkeykann für Stress-Tests von Applikationen eingesetzt werden. Ein Beispiel für einenAufruf von Monkey ist: adb shell monkey -p org.unsane.spirit -v 500Dadurch wird die Applikation org.unsane.spirit gestartet und es werden 500 pseudo-zufällige Aktionen ausgelöst. Monkeyrunner stellt eine API bereit, über die ein An-droid Device ferngesteuert werden kann.zipalign: Nachdem eine *.apk-Datei signiert wurde, sollte zipalign darauf ange-wandt werden, da es an dieser weitere Optimierungen durchführt.Weitere enthaltene Werkzeuge, die an dieser Stelle nicht vorgestellt werden, sind:dmtracedump, hprof-conv, mksdcard, ProGuard, sqlite3, layoutopt und traceview.

SDK Platform-tools

Die SDK Platform-tools enthalten ebenfalls Werkzeuge, mit denen eine Android-Applikation entwickelt und debuggt werden kann. Sie sind im Unterverzeichnisplatform-tools des SDK verfügbar. Einige dieser Werkzeuge (aidl, aapt, dexdumpund dx) werden normalerweise nicht direkt aufgerufen. Der Aufruf erfolgt meist

5Vgl. http://wiki.qemu.org/Main_Page6Graphical User Interface

Sebastian Stallenberger Seite 11 von 104

Page 16: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

2. Vorstellung der Technologien Fachhochschule Schmalkalden SS 2011

über die Android-build-tools oder Android-Development-Tools (ADT). Im Folgen-den wird eines dieser Werkzeuge - die Android-Debug-Bridge (adb) - kurz vorgestellt.Soweit nicht anders angegeben, gilt [Goo11b] als Quelle für dieses Unterkapitel.Die Android-Debug-Bridge ist ein Kommandozeilen-Tool. Sie ermöglicht es, mit ei-nem Emulator oder einem verbundenen Device zu kommunizieren. Sie besteht dabeiaus drei Komponenten:

• Dem Client, der auf dem Entwicklungs-Rechner läuft. Er kann aus Eclipseheraus über das ADT-Plugin oder aus dem DDMS heraus genutzt werden.Ebenso ist ein direkter Aufruf aus der Konsole über den Befehl adb möglich.

• Dem Daemon, der als Hintergrundprozess in einem Emulator oder einem an-geschlossenen Gerät läuft.

• Dem Server, der im Hintergrund auf dem Entwicklungs-Rechner läuft. Dieserregelt die Kommunikation zwischen den Clients und dem Daemon.

Die ADB kann zum Beispiel dazu genutzt werden, eine Übersicht über die aktu-ell verfügbaren Devices zu bekommen (adb devices), Befehle an spezielle Deviceszu senden (adb -s <IdDesDevice> <Befehl>), Applikationen zu installieren (adbinstall <PfadZumAPK>) und Dateien auf ein oder von einem Device zu kopieren

(adb pull <entfernterPfad> <lokalerPfad> bzw. adb push <lokalerPfad> <entfernterPfad>). Ebenso können Befehle direkt auf dem Device über eine Remote-Shell ausgeführt werden.Eine vollständige Auflistung aller verfügbaren Befehle ist auf [Goo11b] unter demPunkt „Listing of adb Commands“ verfügbar.

Android platforms

Auf der Android Developers-Website7 sind mehrere Versionen der Android Platformverfügbar (derzeit Version 1.1 - 3.2). Über den AVD Manager können diese in belie-biger Anzahl installiert werden. Hierbei besitzt jede Platform ihre eigene AndroidBibliothek, ein System-Image, Beispiel-Codes und Emulator-Skins. Derzeit ist es vonGoogle so vorgesehen, dass die Android Platforms der Version 2.x für Smartphonesund die der Version 3.x für Tablets genutzt werden. Diese Spaltung soll mit Version4.x aufgehoben werden, die laut [Tom11] im Oktober 2011 auf den Markt kommensoll. Diese Version soll dann einheitlich sowohl auf Smartphones als auch auf Tabletsund anderen Geräten eingesetzt werden können.

USB Driver for Windows

Will man unter Windows seine Applikation auf einem externen Device über USBdebuggen, muss man den im SDK enthaltenen USB-Treiber installieren. Unter MacOS X oder Linux entfällt dieser Schritt.

7Vgl. http://developer.android.com/sdk/adding-components.html

Sebastian Stallenberger Seite 12 von 104

Page 17: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

2. Vorstellung der Technologien Fachhochschule Schmalkalden SS 2011

Samples & Documentation

Diese Verzeichnisse enthalten diverse Code- und Applikations-Beispiele sowie dieaktuelle Dokumentation für jede Android-Development-Platform. Nachdem nun einÜberblick über Android gegeben wurde, geht der Autor im folgenden Kapitel 2.2auf die objektfunktionale Programmiersprache Scala ein.

2.2 ScalaWie schon mehrfach in dieser Arbeit angesprochen, ist Scala eine objektfunktiona-le Programmiersprache. Was dies genau heißt und welche Features Scala mit sichbringt, wird in diesem Kapitel kurz erläutert. Soweit nicht anders angegeben, ist dieQuelle für dieses Kapitel [lan08].Der Name Scala leitet sich von „scalable language“ ab. Laut [OSV08, S. 3] wurde dieSprache so genannt, weil sie mit den Anforderungen der Nutzer wächst. Von kleinenScripten bis hin zu großen Programmen ist alles möglich. In [Bra11, S. 1] findet sichein kurzer geschichtlicher Überblick: „Die Entwicklung begann 2001 an der Écolepolytechnique fédérale de Lausanne (EPFL) in der Schweiz von einem Team umProfessor Martin Odersky. Das erste Release wurde bereits 2003 veröffentlicht. 2006folgte die Version 2.0.“ Inzwischen ist Scala bei Version 2.98 angelangt.Nach [lan08] ist Scala eine Multi-Paradigmen Sprache, die entworfen wurde, umgebräuchliche Entwurfsmuster auf eine möglichst knappe, elegante und typsichereWeise umzusetzen. Die Objektorientierung wurde hierbei sehr streng umgesetzt. Sosind alle Werte Objekte. Das betrifft auch numerische Werte oder Funktionen. Be-schrieben werden diese Objekte in Klassen oder sogenannten Traits. Traits sind denInterfaces in Java ähnlich. Anders als in Java-Interfaces können in Traits Methodenimplementiert werden. Dadurch wird eine Realisierung von Rich-Interfaces ermög-licht. Im Gegensatz zu Klassen dürfen Traits allerdings keine Konstruktor-Parameterhaben. [Bra11, S. 2]Laut [Bra11, S. 2] nennt Odersky Scala nach einigen Diskussionen im Web eine post-funktionale Sprache. So können Funktionen sowohl Argumente als auch Ergebnissevon anderen Funktionen sein. Ebenso ist die Verschachtelung von Funktionen mög-lich. Weiterhin unterstützt Scala Pattern-Matching und Currysierung. Die statischeTypisierung sieht [OSV08, S. 12-19] als einen großen Vorteil von Scala gegenüberSprachen mit dynamischer Typisierung. So gibt es ein System von ineinander ver-schachtelten Typen, es können aber auch Typen mit Generics parametrisiert werden.Weiterhin machen es Intersections möglich, Typen zu kombinieren. Abstrakte Typenermöglichen es, Typ-Details zu verstecken.Tiefer in die Theorie von Scala einzusteigen, würde den Umfang dieser Arbeit spren-gen. Für detaillierte Informationen über Scala empfiehlt der Autor [Bra11], [OSV08]und [lan08] zur Lektüre. Nachdem im aktuellen Kapitel die beiden TechnologienAndroid und Scala kurz vorgestellt wurden, stellt der Autor im nächsten KapitelEntwicklungsumgebungen für Android und Scala vor.

8Vgl. http://www.scala-lang.org/downloads

Sebastian Stallenberger Seite 13 von 104

Page 18: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

3 EntwicklungsumgebungenDie Entwicklung einer Software mit einer Kombination von Technologien, die vomStandard abweicht, stellt einen gleich zu Beginn vor das Problem der Auswahl einergeeigneten Entwicklungsumgebung. Netbeans1 entfällt als Möglichkeit, da es der-zeit keine stabile2 Scala-Unterstützung bietet. Die einfachste Methode ist der Wegüber die Konsole. Hierbei entfällt zwar aller Ballast, aber auch jegliche Hilfestellung,die moderne Entwicklungsumgebungen mit sich bringen. Als Editor kann jeder be-liebige Texteditor genutzt werden, z.B. vim3 (alle Plattformen) oder Notepad++4

(Windows). Der dem Entwickler gebotene Komfort hängt vom genutzten Editor ab.Mit Eclipse5 und IntelliJ 6 bieten sich zwei Entwicklungsumgebungen an, die sich be-sonders in der Java-Entwicklung einen Namen gemacht haben. Eclipse wird von Goo-gle für die Android-Programmierung empfohlen und gilt somit als offizielle Android-Entwicklungsumgebung. Die Unterstützung für Android ist dementsprechend um-fangreich. Von einem professionellen GUI-Editor über Code-Completion bis hin zurVisualisierung des AndroidManifest bietet Eclipse alles, was das Herz eines Android-Entwicklers begehrt. Für Scala existieren wenige Eclipse-Plug-ins. Das bekanntesteist Scala IDE for Eclipse7.IntelliJ galt lange als beste Entwicklungsumgebung für die Scala-Programmierung.Das Scala-Plug-in ist vorinstalliert und auch für SBT (Simple Build Tool) und An-droid finden sich entsprechende Plug-ins, die unabhängig voneinander betrachtetgute Dienste leisten.Wie sich die drei Methoden jeweils in der Praxis in Bezug auf Android und Scalaverhalten, wird in den folgenden Abschnitten kurz dargestellt. Ausführlichere An-leitungen befinden sich im Anhang A.1.

3.1 VorbereitungenVoraussetzung für alle in diesem Kapitel angesprochenen Möglichkeiten sind dasJDK8, Scala SDK9 und Android SDK10. Die Konfiguration erfolgte unter Windows 7.

1http://www.netbeans.org2Vgl. http://www.scala-lang.org/node/353 „Not perfect, but fairly stable“3http://www.vim.org4http://notepad-plus-plus.org5http://www.eclipse.org6http://www.jetbrains.com7Vgl. http://www.scala-ide.org8http://www.oracle.com/technetwork/java/javase/downloads/index.html9http://http://www.scala-lang.org/downloads

10http://developer.android.com/sdk/index.html

Sebastian Stallenberger Seite 14 von 104

Page 19: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

3. Entwicklungsumgebungen Fachhochschule Schmalkalden SS 2011

Unter Linux oder MacOs können die Ergebnisse abweichen. Als Root-Pfad für alleSDKs gilt C:\scalandroid.Nach dem Entpacken aller SDKs im oben genannten Verzeichnis sollte man dasAndroid SDK updaten und konfigurieren. Dies kann über den im Android SDK ent-haltenen SDK Manager erledigt werden. Nach den Updates erstellt man ein Device„SpiritDevice“11 mit Android 2.2 - API-Level 8 12. Damit ist die Einrichtung derSDKs abgeschlossen und man kann sich der Auswahl eines Build Tools zuwenden.Ein bei Scala-Entwicklern sehr beliebtes Tool ist hierbei das SBT. Auch wird esin dieser Arbeit als Build-Tool eingesetzt werden, da es sich unabhängig von derEntwicklungsumgebung in Kombination mit Android unterstützenden Plug-Ins alssehr gut funktionierendes Werkzeug bewiesen hat. SBT kann man auf der Projekt-Homepage13 herunterladen. Abgelegt wurde das SBT für unser Projekt auch imRoot-Ordner.Anschließend wird das SBT nach der Anleitung auf der Projekt-Homepage14 ein-gerichtet. Der detailliertere Einsatz von SBT wird im Kapitel A.1.3 erläutert. Fürdas Scala SDK, Java SDK und SBT sollten gültige Umgebungsvariablen angelegtwerden, falls noch nicht geschehen. Details dazu finden sich im Kapitel A.1.2.

3.2 KonsoleUm mit dem SBT Scala-Android-Projekte zu erstellen, ist ein SBT-Plugin von Nö-ten. Vorgefertigt findet man ein solches in GIT-Hub15. Im Ordner android-plugin\script findet man ein Shellscript, das man unter Windows natürlich nicht ohne wei-teres ausführen kann. Nachdem vorherige Versuche mit MinGW16 und Cygwin17

fehlschlugen, führte eine Abänderung des Shellscripts zum Erfolg. Die Änderungkann in Kapitel A.1.3 nachgelesen werden. Damit konnte ohne Probleme ein voll-ständiges Android-Projekt18 erstellt werden. Das erzeugte Android-Projekt weist diein Listing 3.1 gezeigte Struktur auf. Die Konfigurations-Daten für SBT befinden sichin der Datei project\build\SpiritMobile.scala.Im nächsten Schritt kann der Android-Emulator per emulator -avd SpiritDevicegestartet werden.Die folgende Reihenfolge sollte bei der ersten Verwendung von SBT eingehaltenwerden.

• sbt update - Läd die benötigten Abhängigkeiten herunter. Muss nur einmaligbei der ersten Verwendung oder bei Änderungen in der SBT-Konfigurationausgeführt werden.

11Der Name kann hier frei gewählt werden. In dieser Arbeit wird allerdings immer auf „SpiritDe-vice“ verwiesen.

12Warum genau diese Version, wurde im Kapitel 1.5 schon erläutert.13http://code.google.com/p/simple-build-tool/downloads/list14Vgl. http://code.google.com/p/simple-build-tool/wiki/Setup15Im Root-Ordner git clone git://github.com/jberkel/android-plugin.git ausführen16http://sourceforge.net/projects/mingw/17Vgl. http://www.horstmann.com/articles/cygwin-tips.html18Vgl. http://zegoggl.es/2009/12/building-android-apps-in-scala-with-sbt.html

Sebastian Stallenberger Seite 15 von 104

Page 20: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

3. Entwicklungsumgebungen Fachhochschule Schmalkalden SS 2011

• sbt package-debug - führt den Build-Vorgang durch und erzeugt ein *.apk-Paket.

• sbt reinstall-emulator - Installiert das Paket in den Emulator.

Listing 3.1: Die Verzeichnisstruktur des mit android-plugin erzeugten Projekts.|-- project| |-- build| | ‘-- SpiritMobile .scala| |-- build. properties| ‘-- plugins| ‘-- Plugins .scala|-- src| |-- main| | |-- AndroidManifest .xml| | |-- assets| | |-- java| | |-- res| | | |-- drawable| | | |-- layout| | | |-- values| | | ‘-- xml| | ‘-- scala| | ‘-- Activity .scala| ‘-- test| ‘-- scala| ‘-- Specs.scala‘-- tests

Hat man vorher nicht die Umgebungsvariable ANDROID_SDK_HOME gesetzt, teilt einemSBT das nun mit.Die apk Pakete wurden somit erzeugt, zwischengespeichert und anschließend aufdem laufenden Emulator installiert. Dort kann man in der Programmauswahl dieAnwendung SpiritMobile wählen und ausführen. Ein einfaches „hello, world“ wirdausgegeben. Das bestehende Projekt kann nun weiterentwickelt werden. Schritte zurDistribution der Anwendung werden im Kapitel 7 behandelt.

3.3 EclipseIn diesem Kapitel wird nur eine funktionierende Methode zur Einrichtung von Eclip-se vorgestellt. Andere missglückte Versuche sind im Anhang in Kapitel A.1.4 doku-mentiert. Die Quellen für dieses Kapitel sind [Sø11b] und [Sø11a].Treeshaker nennt sich ein Projekt, das durch Einfügen eines Build-Schritts die Nut-zung von Scala auf Android ermöglicht. In diesem Build-Schritt werden die erzeugtenJava und Scala *.class-Dateien auf ihre Abhängigkeit die Scala Bibliothek betreffenduntersucht. Diese Abhängigkeiten werden dann in das bin-Verzeichnis exportiert undvon den Android-Build-Tools in das erzeugte *.apk-Paket mit aufgenommen.

Sebastian Stallenberger Seite 16 von 104

Page 21: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

3. Entwicklungsumgebungen Fachhochschule Schmalkalden SS 2011

Im Folgenden werden die nötigen Schritte zur Einrichtung des Treeshaker-Pluginserläutert19. Voraussetzung für Treeshaker sind eine funktionierende Android SDKund Eclipse Installationen. Anschließend installiert man die Scala IDE 20 in Eclip-se. Das zweite zu installierende Plugin ist Treeshaker21 selbst. Nun kann ein neuesAndroid Projekt erzeugt werden. Dabei ist darauf zu achten, eine Activity namens„Main“ erzeugen zu lassen. Im nächsten Schritt wird das Verzeichnis src in _src um-benannt und die Scala- und Treeshaker-Nature22 zum Projekt hinzugefügt. In denProjekteigenschaften sollte jetzt die Build-Reihenfolge auf ihre Korrektheit über-prüft werden:

• Android Resource Manager• Android Pre Compiler• Scala Builder• Treeshaker• Android Package Builder

Nachdem die Datei Main.java durch eine Main.scala ersetzt wurde, kann mit demProgrammieren in Scala begonnen werden.Anmerkung: Kurz vor Fertigstellung dieser Arbeit entdeckte der Autor eine weitereMethode, Scala, Android und Eclipse zusammenzubringen. Diese kann im eSCALA-tion blog23 eingesehen werden, wurde aber nicht vom Autor getestet.

3.4 IntelliJNeben Eclipse bietet sich mit IntelliJ eine weitere Entwicklungsumgebung an, diesowohl Android- als auch Scala-Programmierung unterstützt. Auch hier bestehenwieder diverse Möglichkeiten, die Umgebung für die Entwicklung von Android-Applikationen mit Scala einzurichten. Der Autor geht allerdings nur auf eine funk-tionierende Methode näher ein.Die Methode basiert auf dem mit dem android-plugin24 erstellten Projekt aus demKapitel 3.2. Nachdem das Projekt erstellt wurde, müssen in IntelliJ einige Anpas-sungen vorgenommen werden. Die Schritt-für-Schritt-Anleitung und Lösungen füreventuell auftretende Probleme sind im Anhang in Kapitel A.1.5 zu finden.

3.5 Wahl für die ArbeitZum Zeitpunkt der Recherche zum Thema Entwicklungsumgebungen im März 2011funktionierte die Treeshaker-Methode für Eclipse noch nicht ohne Probleme. Es

19Basierend auf den am Anfang des Kapitels genannten Quellen.20Es ist hierbei wichtig, nicht Scala 2.9 zu nutzen, da dies noch Probleme mit den Android-Build-

Tools auslöst. Für aktuelle Informationen bitte die Quelle betrachten.21Eclipse-Update-URL: http://treeshaker.googlecode.com/svn/trunk/update_site/22Über das Kontextmenü des Projekts.23Vgl. https://dgronau.wordpress.com/2011/08/20/scala-fur-android-mit-eclipse-leicht-gemacht/24https://github.com/jberkel/android-plugin

Sebastian Stallenberger Seite 17 von 104

Page 22: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

3. Entwicklungsumgebungen Fachhochschule Schmalkalden SS 2011

traten Fehler auf, die auf die Scala IDE zurückzuführen waren. Auch nach Email-Kontakt mit Carsten Elton Sørensen, dem Entwickler von Treeshaker, konnten diesedamals nicht gelöst werden. Mit der neuen, in Installation und Konfiguration sehrvereinfachten Treeshaker-Methode, die jetzt im August 2011 ein weiteres Mal getes-tet wurde, funktioniert zumindest das Demo-Projekt reibungslos. Das fortgeschrit-tene SpiritMobile-Projekt konnte aus Zeitgründen leider nicht mehr in Eclipse zumLaufen gebracht werden.Im März hat sich der Autor aus den oben genannten Gründen für IntelliJ entschie-den. Es bot zum Zeitpunkt des Starts der Implementation den reibungslosestenWorkflow. Gelegentlich traten allerdings auch hier Probleme auf, die man alle abermehr oder weniger gut umgehen kann. Es sei nochmal ausdrücklich gesagt, dass In-telliJ nicht die perfekte Wahl darstellt. Wer mag, kann auch einfach die Konsole undSBT nutzen, da IntelliJ im Fall des vorgestellten Projekts nichts weiter macht, alsSBT fernzusteuern und eine angenehme Programmierumgebung bereitzustellen. Eingroßer Vorteil der Nutzung von SBT (egal ob über IntelliJ oder Konsole) ist, dassProguard25 immer mit ausgeführt wird. Proguard reduziert den Code auf die nötigenElemente und optimiert ihn, indem es z.B. ungenutzte Klassen und Methoden ausdem Code entfernt.Nachdem in diesem Kapitel eine geeignete Entwicklungsumgebung für SpiritMobilegesucht wurde, werden im folgenden Kapitel die Anforderungen an die Anwendunganalysiert und festgelegt.

25Vgl. http://proguard.sourceforge.net/

Sebastian Stallenberger Seite 18 von 104

Page 23: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

4 AnforderungsanalyseDa für diese Arbeit kein externer Auftraggeber existiert, wurden die Anforderungenin Team-Besprechungen und in Absprache mit Prof. Dr. Braun definiert.Ziel ist die Entwicklung des Android-Client SpiritMobile. Hierbei soll statt der fürAndroid typischen Sprache Java die objekt-funktionale Sprache Scala eingesetzt wer-den. Im Folgenden werden nun die geforderten Features dargestellt.

4.1 Erforderliche FeaturesBei den Features kann zwischen erforderlich und optional unterschieden werden. Indiesem Abschnitt wird kurz auf die erforderlichen Features eingegangen.Standalone Modus:SpiritMobile soll einen Modus besitzen, in dem es eigenständig, ohne externe Da-tenquellen und andere Abhängigkeiten funktioniert. Dies soll gewährleisten, dassdas Programm auch ohne die anderen Spirit-Komponenten genutzt werden kann.Mindestens die Anzeige von Informationen soll auf diese Weise verfügbar sein.Darstellung von Informationen:Das News-System ist eines der wichtigsten Komponenten von Spirit. Dem Nutzersollen die News und die dazu gehörigen Kommentare in einem übersichtlichen Layoutdargestellt werden. Die Darstellung des individuellen Stundenplans ist eine weite-re Herausforderung. Hierbei sind feste Zeitfenster für die einzelnen Appointmentsvorgesehen.Kommunikation:Der Daten-Austausch aller Features soll über REST geschehen. Hierzu steht eineREST-Schnittstelle bereit, die vom Spirit-Team konzipiert wurde. Betreffend desFormats für die Übermittlung kann zwischen XML und JSON gewählt werden.Warum JSON hier vorzuziehen ist, wird in Abschnitt 5.8 erläutert.

4.2 Optionale FeaturesIn diesem Abschnitt werden kurz die optionalen Features aufgezeigt.Informationen anlegen/löschen: Dem Nutzer soll es ermöglicht werden, abhän-gig von seinem Login-Status, News und Kommentare zu verfassen. Auch sollen Newsund Kommentare gelöscht werden können, wenn der eingeloggte Nutzer auch derAutor ist.Login: Dem Nutzer soll es möglich sein, sich mit seiner FHS-ID einzuloggen. Danachsoll auch die Rolle des Nutzers im System festgelegt werden. Je nach Rolle (z.B.

Sebastian Stallenberger Seite 19 von 104

Page 24: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

4. Anforderungsanalyse Fachhochschule Schmalkalden SS 2011

Student oder Professor) hat der Nutzer bestimmte Privilegien. Auch das Haupt-Menü soll sich abhängig von der Rolle ändern.Einstellungen: Dem Nutzer soll es möglich sein, persönliche Einstellungen (wieLogin-Daten, News-Filter usw.) über ein Einstellungsmenü festzulegen. Dieses Menüsoll vom Hauptmenü aus erreicht werden können.Filter: News sollen zum Beispiel nach einem bestimmten Semester, Studiengangoder Lehrenden gefiltert werden können, um den Nutzer nicht mit Informationen zubelästigen, die er nicht benötigt.Intuitives Design: Die GUI der Applikation sollte möglichst schlicht und intui-tiv gestaltet werden. Auch weniger technikaffine Nutzer sollen sie ohne zusätzlicheInformationen bedienen können.Mehrsprachigkeit: Die Default-Sprache der Applikation ist Deutsch. Alternativsollte für englische Systeme Englisch angeboten werden. Android stellt hierfür ein-fache Mechanismen bereit, die genutzt werden können. Damit könnten in Zukunftohne Probleme auch weitere Sprachen eingebunden werden.

Sebastian Stallenberger Seite 20 von 104

Page 25: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

5 EntwurfIn diesem Kapitel wird darauf eingegangen, wie die geforderten Features mit Androidund Scala umgesetzt werden können.Hinter SpiritMobile steckt ein modulares Konzept. Features, die in Zukunft neuhinzukommen werden, sollen möglichst einfach in die bestehende Anwendung einge-gliedert werden können. Die Android Activities bilden hierzu die Basis. Beim Aufbauder Applikation wurde eine Art Baum-Struktur gewählt, die aber trotzdem Verbin-dungen zwischen den einzelnen Ästen zulässt. Eine alternative Anordnung wäre,das Hauptmodul wegzulassen und die Module parallel anzuordnen. Diese könntendann durch ein „Wischen“ mittels eines sogenannten Spinner1 gewechselt werden,ähnlich des Wechsels der verschiedenen Desktops unter Android. Aus zwei Gründenentschied sich der Autor für die Baum-Struktur: Zum einen erzwingt die paralleleAnordnung eine Reihenfolge. Will der Nutzer also zum TimeTable, muss er vor-her erst alle anderen Module durch-scrollen. Zum Anderen ist die „Wisch“-Methodeideal, um im TimeTable zwischen den einzelnen Tagen zu navigieren und soll da-her dafür vorbehalten werden. Die Root-Activity MainActivity, die beim Start derApplikation geladen wird, enthält das Hauptmenü.

Abbildung 5.1: Möglichkeiten der Nutzer-Navigation durch die Module

Wie man in Abbildung 5.1 sieht, laufen von MainActivity aus Äste zu NewsMulti,NewsCreate, TimeTable und Settings. Wird in NewsCreate erfolgreich eine Newsangelegt, wird der Nutzer zu NewsMulti weitergeleitet. Das Anklicken einer Newsin NewsMulti führt den Nutzer zu NewsSingle. In den folgenden Unterkapiteln wirdauf die einzelnen Module inklusive der MainActivity eingegangen.

1Vgl. http://developer.android.com/reference/android/widget/Spinner.html

Sebastian Stallenberger Seite 21 von 104

Page 26: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

5. Entwurf Fachhochschule Schmalkalden SS 2011

5.1 MainActivityDie MainActivity enthält neben dem Hauptmenü auch das Spirit Logo. Es bestehenmehrere Möglichkeiten der Anordnung, wie die Abbildung 5.2 zeigt.

Abbildung 5.2: Vorschläge zur Anordnung der Menü-Elemente

In beiden Anordnungen ist das Logo über dem Menü positioniert. In AnordungA sind die Menü-Elemente in einer zweispaltigen Tabelle angeordnet. In Androidkann man das entweder mit einem TableLayout2 oder aber mit einer GridView3

realisieren. Vorteil an dieser Anordnung ist der Platz, der in den einzelnen Elemen-ten für z.B. Symbole bereitsteht. In Anordnung B sind die Elemente wie eine Listeuntereinander angeordnet. Realisieren lässt sich so etwas in Android mit einem Re-lativeLayout4, einem LinearLayout5 oder einfach mit einer ListView6. Vorteilhaft istdiese Anordnung bei Menü-Elementen, in denen Texte dominieren, und wenn vieleMenü-Elemente dargestellt werden müssen.Für die Arbeit wurde Anordnung A gewählt. Zum einen ist die Anzahl der Menü-Elemente relativ gering. Zum anderen sind quadratische Flächen für den Nutzereinfacher zu treffen. Die Möglichkeit des Einsatzes großer Symbole ist ein weitererBonus. Umgesetzt werden soll das Layout mit einer GridView.Je nach Rolle werden im Menü folgende Elemente angezeigt:

• Nicht eingeloggt: Neues (NewsMulti)• Rolle „Student“: Neues (NewsMulti), Stundenplan (TimeTable)• Rolle „Professor“: Neues (NewsMulti), Neues verfassen (NewsCreate), Stun-

denplan (TimeTable)2Vgl. http://developer.android.com/reference/android/widget/TableLayout.html3Vgl. http://developer.android.com/reference/android/widget/GridView.html4Vgl. http://developer.android.com/reference/android/widget/RelativeLayout.html5Vgl. http://developer.android.com/reference/android/widget/LinearLayout.html6Vgl. http://developer.android.com/reference/android/widget/ListView.html

Sebastian Stallenberger Seite 22 von 104

Page 27: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

5. Entwurf Fachhochschule Schmalkalden SS 2011

Die Einstellungen (Settings) werden ins Options menu7 ausgelagert, das sich öffnet,wenn der Nutzer die „Menu“-Taste des Smartphones betätigt.Im nächsten Abschnitt wird auf die Activity NewsMulti eingegangen.

5.2 NewsMultiDa sich die Anzeige der News vertikal stark ausdehnen kann, sollte dafür ein Basis-Layout mit eingebauter Scroll-Funktion genutzt werden. Alternative dazu ist derEinsatz einer ScrollView8. Der Autor hat sich für eine Kombination aus ScrollViewund LinearLayout entschieden.Der dynamische Aufbau der Layouts in SpiritMobile wird manuell durchgeführt.Alternative wäre der Einsatz einer ListView mit Adaptern9 und LayoutInflatern10,was die Aufgabe deutlich vereinfachen würde. Der manuelle Aufbau hat allerdingsdie großen Vorteile, dass man flexibler ist und die Konstruktion vonstatten geht, dader Aufbau an die darzustellenden Objekte perfekt angepasst ist.Die einzelnen News sollen jeweils aus einem RelativeLayout bestehen. Dies hat denVorteil, dass Elemente nicht nur vertikal, horizontal oder in Grid-Form angeordnetwerden können, sondern in fast beliebigen Kombinationen. Dabei wird für jedesElement mindestens eine Abhängigkeit zu einem anderen Element angegeben. AuchAbhängigkeiten zu Eltern-Elementen sind möglich.

Abbildung 5.3: Aufbau von NewsMulti und der einzelnen News-Elemente

7Wird im Kapitel 6.3.4 detailliert erläutert.8Vgl. http://developer.android.com/reference/android/widget/ScrollView.html9Vgl. http://developer.android.com/reference/android/widget/Adapter.html

10Vgl. http://developer.android.com/reference/android/view/LayoutInflater.html

Sebastian Stallenberger Seite 23 von 104

Page 28: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

5. Entwurf Fachhochschule Schmalkalden SS 2011

Wie man in Abbildung 5.3 sieht, ist über den News-Elementen ein Element geplant,das dem Nutzer den Zeitpunkt des letzten Updates zeigt. Sind mehr News-Elementeanzuzeigen als auf den Bildschirm passen, wird der komplette Inhalt vertikal ge-scrollt.Ein einzelnes News-Element besteht aus vier Bereichen: Dem Header, dem Bereichfür DegreeClass, dem Content und dem Footer. Den Header teilen sich der Title (dieÜberschrift der News) und das Datum der letzten Änderung. Sollte der Title längersein als der Platz, der ihm zusteht, wird er gekürzt und bekommt „...“ als Abschluss.Unter dem Header ist eine Zeile für DegreeClass reserviert. DegreeClass sind die Nut-zergruppen, die die News betrifft, zum Beispiel „MAI3“ oder „BaI4“. Im Mittelteildes News-Elements befindet sich der Content11. Dieser ist in der MultiNews-Ansichtallerdings auf eine Zeile beschränkt und wird bei längeren Texten gekürzt und mit„...“ abgeschlossen. Der Footer enthält den Owner (Eigentümer) der News und dieAnzahl der Kommentare, die zu der News abgegeben wurden.Die Kürzung der Elemente mit Überlänge ermöglicht einen kompakten, einheitlichenÜberblick über alle News-Elemente. Filterkriterien für News sind das Zeitintervall,der Owner und die Zielgruppen12, an die die News gerichtet sind. Die Auswahlder Filter kann entweder in den allgemeinen Settings oder in einem Option Menuerfolgen.News des aktuell eingeloggten Nutzers werden farblich hervorgehoben, um zwischeneigenen und fremden News einfacher unterscheiden zu können. Eigene News könnenvom Nutzer gelöscht werden. Klickt der Nutzer lang auf seine eigene News, fragt ihnein Dialog, ob er die News auch wirklich löschen will.Die News werden in folgenden Situationen neu abgerufen:

• Der Nutzer kommt von MainActivity.• Der Nutzer betätigt den Reload-Button im Option Menu.• Der Nutzer hat in NewsSingle einen neuen Comment angelegt und kehrt zu

NewsMulti zurück.• Der Nutzer hat eine neue News in NewsCreate erfolgreich angelegt.

Ist zum Zeitpunkt des Reloads keine Internetverbindung vorhanden, wird dies demNutzer in einem Toast13 mitgeteilt.Im nächsten Abschnitt wird auf die NewsSingle-Activity eingegangen, die ein Nutzersieht, wenn er eine News anklickt.

5.3 NewsSingleDie Einzel-Ansicht NewsSingle unterscheidet sich von der NewsMulti schon dadurch,dass Title und Content nicht mehr gekürzt werden. Beide Felder erweitern sichdynamisch angepasst an den Text vertikal. Sonst entspricht der Aufbau des News-Elements dem in NewsMulti.

11also der Inhalt der News12im Datenmodell „DegreeClass“ genannt13Vgl. http://developer.android.com/reference/android/widget/Toast.html

Sebastian Stallenberger Seite 24 von 104

Page 29: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

5. Entwurf Fachhochschule Schmalkalden SS 2011

Abbildung 5.4: Aufbau von NewsSingle, des Comment-Blocks und eines einzelnenComment-Elements

NewsSingle ist dabei aufgeteilt in einen Bereich für die News und einen Bereichfür die dazugehörigen Comments. Im Comment-Bereich werden alle Comments derNutzer mit den Daten Owner, Date und Content aufgelistet, wie aus der Abbil-dung 5.4 zu entnehmen ist. Ist der Nutzer eingeloggt und hat die dementsprechendeBerechtigung, erscheint unter der Comments-Auflistung ein Eingabefeld, über dasein neuer Comment eingetragen werden kann. Der Send-Button befindet sich unterdiesem Eingabefeld. Comments des aktuell eingeloggten Nutzers werden auch hierfarblich hervorgehoben. Eigene Comments können auf dieselbe Art und Weise wiebei den News gelöscht werden.Wurde ein Comment angelegt, wird die dazugehörige News komplett neu geladenund die Ansicht in NewsSingle aktualisiert. Bei Rückkehr zu NewsMulti wird auchdort ein Reload durchgeführt, um die Anzahl der Comments korrekt anzeigen zukönnen. Schlägt das Senden eines Comments fehl, wird der Nutzer darüber in einemToast informiert.Das folgende Kapitel befasst sich mit der Activity NewsCreate, in der neue Newsangelegt werden können.

5.4 NewsCreateIst dem aktuell eingeloggten Nutzer die Rolle „Professor“ zugeordnet, wird ihm imHauptmenü das Menü-Element für NewsCreate angezeigt. Wie in Abbildung 5.5dargestellt, wird als Basis-Layout ein LinearLayout gewählt.Der Nutzer kann im EditText14 Subject den Betreff und im EditText Message dieNachricht eingeben. Die betreffenden DegreeClasses und das ExpireDate werden

14Vgl. http://developer.android.com/reference/android/widget/EditText.html

Sebastian Stallenberger Seite 25 von 104

Page 30: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

5. Entwurf Fachhochschule Schmalkalden SS 2011

Abbildung 5.5: Aufbau von NewsCreate

in Buttons angezeigt. Ein Klick auf den DegreeClass-Button öffnet ein Popup miteiner Mehrfachauswahl, die alle verfügbaren DegreeClasses enthält. Beim Klick aufExpireDate öffnet sich ein Popup mit einem DatePicker.Ein Klick auf den Send-Button sendet die News an den Server. War das Eintragenerfolgreich, wechselt die Ansicht zu NewsMulti. Schlug es fehl, wird der Nutzer dar-über in einem Toast informiert und die Ansicht mit allen Eingaben bleibt erhalten.

5.5 TimeTableDie technischen Hintergrundprozesse des TimeTable gestalten sich verhältnismäßigeinfach, da der TimeTable nur angezeigt werden soll und keine eigenen Appointmentseingetragen werden können. Wie in Abbildung 5.6 dargestellt, unterscheidet sich derAufbau des TimeTable je nach Lage des Geräts:

• Vertikale Lage: Es wird eine Ein-Tages-Ansicht dargestellt. Am oberen Randdes Bildschirms befindet sich eine Navigations-Leiste mit dem Datum des an-gezeigten Tags sowie Vor- und Zurück-Buttons. Will man den Tag wechseln,kann das durch Klicken der Buttons oder aber durch einfaches Wischen in dieentsprechende Richtung bewirkt werden. Die Ansicht eines einzelnen Tagesist in Zeitabschnitte (folglich genannt TimeSlots) unterteilt. Die Zeitintervallefür die TimeSlots wurden nach dem Vorbild des Stundenplans des FachbereichInformatik festgelegt. Für jeden TimeSlot können bis zu drei Appointments(Termine) angezeigt werden. Ein Klick auf einen TimeSlot öffnet die Detail-ansicht, auf die in Kapitel 5.6 eingegangen wird.

• Horizontale Lage: Ähnlich wie bei der Ein-Tages-Ansicht gibt es in der Wochen-Ansicht eine Navigationsleiste am oberen Bildschirmrand. Die Bedienung ent-spricht dabei der der Ein-Tages-Ansicht. Diese Ansicht ist rein dazu gedacht,sich einen Überblick zu verschaffen. Ein Klick auf die Tage oder Appointmentsbewirkt nichts.

Sebastian Stallenberger Seite 26 von 104

Page 31: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

5. Entwurf Fachhochschule Schmalkalden SS 2011

Abbildung 5.6: Aufbau des TimeTable in vertikaler und horizontaler Lage

Im folgenden Abschnitt wird der Entwurf eines Timeslots detaillierter dargestellt.

5.6 TimeSlotIn einem Header wird das zum TimeSlot gehörige Datum und das Zeitintervallangezeigt. Darunter werden alle Appointments, die den Timeslot belegen, aufgelistet.Daten der einzelnen Appointments sind, wie in Abbildung 5.7 zu sehen:

• Name des Events, zu dem das Appointment gehört.• Status des Appointments. Hier wäre auch eine farbliche Kennzeichnung mög-

lich (z.B. ausgegraut für canceled).• Die Location des Appointments.• Der Lecturer des Appointments.

5.7 SettingsFür die Settings-Activity wird nicht Activity als Basis gewählt. Android stellt mitder PreferenceActivity ein ideales Grundgerüst für eine Activity bereit, über dieEinstellungen getätigt werden sollen. Was die PreferenceActivity von Activity un-terscheidet, wird im Kapitel 6 näher beleuchtet.Die Settings-Activity ist in vier Abschnitte unterteilt:

• Login section: Enthält Eingabefelder für die FHS-Id und das Passwort. Hierkönnte auch noch der Login-Status angezeigt werden.

Sebastian Stallenberger Seite 27 von 104

Page 32: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

5. Entwurf Fachhochschule Schmalkalden SS 2011

Abbildung 5.7: Aufbau der Detailansicht eines Timeslots

• News section: Bietet Filter-Optionen für die News an.• TimeTable section: Hier kann der Nutzer Einstellungen treffen, die den Time-

Table betreffen.• Other: Enthält sonstige Einstellungen wie zum Beispiel eine Checkbox für den

Standalone-Modus.

Abbildung 5.8: Aufbau von Settings

Ein schematischer Entwurf von Settings ist in Abbildung 5.8 zu sehen. Neben denbisher vorgestellten Activities, die der Nutzer sehen kann, gibt es auch einige Hin-tergrundprozesse, die im Folgenden näher beschrieben werden.

Sebastian Stallenberger Seite 28 von 104

Page 33: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

5. Entwurf Fachhochschule Schmalkalden SS 2011

5.8 Entwürfe von HintergrundprozessenIn diesem Abschnitt werden mögliche im Hintergrund ablaufende Prozesse skizziertund beschrieben. Jede Kommunikation findet über die im Team definierte REST-Schnittstelle statt. Als Datenformat wurde JSON gewählt, da dieses Format einendeutlich geringeren Overhead15 hat als XML. Laut [jso11] ist JSON für Menschenaußerdem besser les- und schreibbar und für Maschinen einfacher zu parsen und zugenerieren.

5.8.1 News oder TimeTable abrufen

Wie im Kapitel 5.2 angesprochen, werden die News in diversen Situationen neu abge-rufen. In Abbildung 5.9 ist skizziert, wie dieses Abrufen ablaufen könnte. Der Autor

Abbildung 5.9: Abruf-Algorithmus in NewsMulti

geht von einer der im Kapitel 5.2 genannten Nutzer-Aktionen aus. Im ersten Schrittwird überprüft, ob eine Internetverbindung vorhanden ist. Sollte dies nicht der Fallsein, wird geprüft, ob im Speicher des Geräts schon ein älterer JSON-String vor-handen ist. Ist dies auch nicht der Fall, sieht der Nutzer eine Fehlermeldung. Ist imSpeicher ein JSON-String vorhanden, wird dieser geladen, in ein Objekt gewandeltund zurückgegeben.15Vgl. https://secure.wikimedia.org/wikipedia/de/wiki/Overhead_%28EDV%29

Sebastian Stallenberger Seite 29 von 104

Page 34: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

5. Entwurf Fachhochschule Schmalkalden SS 2011

Ist eine Internetverbindung vorhanden, stellt SpiritMobile eine Anfrage an den Ser-ver. Wenn diese fehlschlägt, wird dem Nutzer wieder eine Fehlermeldung angezeigt.Ist die REST-Abfrage allerdings erfolgreich, passieren drei Dinge:

• Der JSON-String wird für den Offline-Gebrauch im Speicher abgelegt. Sollteeinmal ein Service für den regelmäßigen News-Abruf implementiert werden,kann dieser String auch dazu genutzt werden, um zu entscheiden, ob neueNews vorhanden sind oder nicht.

• Das Datum des letzten Abrufs wird festgesetzt. Wie schon beschrieben, wirddieses Datum in der Header-Zeile von NewsMulti angezeigt.

• Der JSON-String wird in ein Objekt umgewandelt und dies wird zurückgege-ben.

Der Abruf einzelner News erfolgt nur, wenn ein neuer Kommentar angelegt wurde.Der Ablauf der dazugehörigen Abfrage ist ähnlich und wird daher hier nicht nocheinmal skizziert. Allerdings fallen dabei alle Speicheroperationen und das Speicherndes letzten Abruf-Datums weg.Sowohl beim Einzelabruf als auch beim Abruf mehrerer News wird das Layout an-schließend mit den neuen Daten neu geladen.Der Abruf der TimeTable-Daten ist vom Prinzip her mit dem Abruf der News weit-gehend identisch, weshalb an dieser Stelle nicht weiter darauf eingegangen wird.

Abbildung 5.10: Algorithmus des Sendens einer News

Sebastian Stallenberger Seite 30 von 104

Page 35: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

5. Entwurf Fachhochschule Schmalkalden SS 2011

5.8.2 News oder Kommentar erstellen

Die Algorithmen für das Erstellen einer News oder eines Kommentars sind sich sehrähnlich. News zu erstellen ist geringfügig komplizierter, weshalb der Algorithmus andiesem Beispiel skizziert wird.Wie in Abbildung 5.10 zu sehen, wird der Algorithmus auch hier von einer Nut-zeraktion ausgelöst. Das kann z.B. der Klick des Send-Buttons sein. Anschließendfolgt eine Überprüfung auf folgende Voraussetzungen:

• Ist eine Internetverbindung vorhanden?• Sind Subject und Message ausgefüllt?• Ist DegreeClass gesetzt?• Ist das ExpireDate gesetzt und gültig?

Sind alle Voraussetzungen erfüllt, wird eine REST-Anfrage an den Server geschickt.Hat diese Erfolg, wird dem Nutzer eine Erfolgs-Meldung präsentiert und ein Reloadveranlasst, um die gerade eingetragenen Daten anzuzeigen. Ist eine der Vorausset-zungen nicht erfüllt oder schlägt die Anfrage fehl, wird auch hier dem Nutzer eineFehlermeldung angezeigt.Bei Kommentaren wird nur auf die Internetverbindung und Message geprüft.Nachdem in diesem Kapitel ausführlich Entwürfe für die verschiedenen Vorgänge inder Applikation SpiritMobile vorgestellt wurden, wird nun im Kapitel 6 detailliertbetrachtet, ob und wie ausgewählte Problemstellungen in Scala umgesetzt werdenkönnen, die bei der prototypischen Implementierung der Applikation auftraten.

Sebastian Stallenberger Seite 31 von 104

Page 36: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6 Prototypische ImplementierungIn diesem Kapitel werden ausgewählte Probleme, die bei der Implementierung vonSpiritMobile auftraten, und deren Lösungen vorgestellt. Um es dem Leser besserverständlich zu machen, werden prägnante Stellen aus dem Code der Activities undKlassen von SpiritMobile gezeigt und erläutert. Der komplette Code des Prototy-pen von SpiritMobile ist auf Github1 verfügbar. Der Code kann sich in der Im-plementierung allerdings von den im aktuellen Kapitel enthaltenen Code-Auszügenunterscheiden. Das Feature TimeTable ist in der aktuellen Version von SpiritMobilenoch nicht implementiert. Jedoch unterscheidet dieses sich technisch nicht von denin diesen Kapiteln beschriebenen Features und kann deshalb vernachlässigt werden.Viele Code-Beispiele sind noch nicht auf Mehrsprachigkeit ausgelegt und enthaltendeshalb teilweise Strings statt Verweise auf res/values.

6.1 Struktur der ApplikationDie Source-Code-Elemente von SpiritMobile sind unterteilt in drei Gruppen:

• activities: Beinhaltet die Activities, also das Frontend für den Nutzer.• tasks: Beinhaltet die AsyncTasks2, die für Hintergrundprozesse zuständig

sind.• toilers: Beinhaltet Hilfsklassen für SpiritMobile. Dazu zählen z.B. das Con-

nection- und das JSON-Handling.Bevor näher auf die einzelnen Activities eingegangen wird, stellt der Autor dieAsyncTasks näher vor.

6.2 AsyncTasksEine der goldenen Regeln bei der Android Programmierung ist, den UI 3-Threadnicht zu blockieren. Tut man dies trotzdem, bricht nach 5 Sekunden die Anwendungmit dem Dialog „Die Anwendung reagiert nicht mehr“ ab. Um das zu vermeiden, gibtes diverse Möglichkeiten. Die komfortabelste dabei ist der sogenannte AsyncTask.Ein AsyncTask ist ein von Android bereitgestelltes Konstrukt, das es ermöglicht,Operationen im Hintergrund auszuführen und die Ergebnisse anschließend wiederim UI-Thread anzuzeigen. Dabei müssen keine Threads oder Handler manipuliertwerden.

1Vgl. https://github.com/spirit-fhs/mobile/2Vgl. http://developer.android.com/reference/android/os/AsyncTask.html3User Interface

Sebastian Stallenberger Seite 32 von 104

Page 37: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Die vier Methoden von AsyncTask sind in ihrer logischen Reihenfolge:• onPreExecute: In dieser Methode werden Operationen ausgeführt, die vor

dem eigentlichen Ausführen der Hintergrund-Operation im UI-Thread gest-artet werden sollen. So kann hier zum Beispiel ein ProgressDialog oder eineProgressBar initialisiert werden.

• doInBackground: Nachdem onPreExecute ausgeführt wurde, wird der In-halt dieser Methode vom Hintergrund-Thread ausgeführt. Die an den Async-Task übergebenen Parameter werden an diese Methode weitergeleitet. DerReturn-Wert dieser Methode wird an onPostExecute übergeben.

• onProgressUpdate:Wird in doInBackground die Methode publishProgressaufgerufen, kann mit onProgressUpdate der UI-Thread aktualisiert werden.So kann zum Beispiel bei einem Download der prozentuale Fortschritt in einerProgressBar aktualisiert werden.

• onPostExecute:Wird wieder vom UI-Thread aufgerufen, nachdem die Hintergrund-Operation abgeschlossen ist. Bekommt das Ergebnis von doInBackground alsParameter.

Neben diesen hat AsyncTask noch die Methode onCancelled, auf die an dieser Stelleaber nicht weiter eingegangen wird.[Goo11d]Der Anfang eines solchen Async-Tasks in Java würde folgendermaßen aussehen:

Listing 6.1: Die ersten zwei Zeilen eines AsyncTasks in Java. Quelle: [Goo11d]private class DownloadFilesTask extends AsyncTask <URL ,

Integer , Long > {protected Long doInBackground (URL ... urls) { [...]

Das Problem ist, dass Scala im Fall von AsyncTasks aktuell keine varargs4 annimmt.Will man also einen AsyncTask in Scala nutzen, muss man laut [Sil11] eine Wrapper-Klasse in Java schreiben, welche die varargs auf ein einzelnes arg reduziert. Wie diesim Fall von SpiritMobile umgesetzt wurde, kann man in Listing 6.2 sehen.

Listing 6.2: Die AsyncTask Wrapper-Klasse in Anlehnung an [Sil11]public abstract class AsyncTaskAdapter <T1 , T2 , T3 >

extends AsyncTask <T1 , T2 , T3 > {protected T3 doInBackground (T1 ... param) {

return doInBackground (param [0]);}

abstract protected T3 doInBackground (T1 param);}

Doch wie sieht denn jetzt eigentlich eine solche Umsetzung eines AsyncTasks inScala aus? In der aktuellen Version von SpiritMobile hat jeder Hintergrundprozessaus Gründen der Übersichtlichkeit seinen eigenen AsyncTask. Diese AsyncTasks sindNewsReloadTask, NewsLoadSingleTask, NewsCreateTask, NewsCommentCreateTaskund VerifyLoginDataTask.

4Zum Beispiel im Listing 6.1 „URL...“.

Sebastian Stallenberger Seite 33 von 104

Page 38: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Am Beispiel des in Listing 6.3 aufgeführten NewsLoadSingleTask wird nun der prin-zipielle Aufbau erläutert. Die Besonderheiten anderer AsyncTasks werden spätererläutert.

Listing 6.3: Code des AsyncTask NewsReloadTaskclass NewsLoadSingleTask ( context: Context ) extends

AsyncTaskAdapter [String , Unit , News] {val progressDialog : ProgressDialog =

ProgressDialog .show(context , "Bitte warten","Die News wird aktualisiert .", true , false)

override protected def onPreExecute {progressDialog .show

}

override protected def doInBackground (param: String) :News = {

SpiritConnect . getSingleNews (context , param)}

override protected def onPostExecute (param: News) {progressDialog . dismiss

val act = context . asInstanceOf [ Activity ]val intent = act. getIntent

intent. addFlags (Intent.FLAG_ACTIVITY_NO_ANIMATION )intent. putExtra (" newSingleNews ", param)act. overridePendingTransition (0, 0)

act.finishact. startActivity (intent)

}}

Als Parameter nimmt die Klasse den context der aufrufenden Activity entgegen. ZuBeginn wird ein ProgressDialog definiert und in der Methode onPreExecute geöff-net. Darauf folgend ruft doInBackground die Methode SpiritConnect.getSingleNews auf. Diese wird im Kapitel 6.5 erläutert. doInBackground übergibt das emp-fangene News-Objekt an onPostExecute. Anschließend wird der Dialog geschlossen,dem Intent5 der Activity die gerade empfangene News als Extra übergeben und dieActivity neu geladen. Die Methode overridePendingTransition(0,0) bewirkt,dass beim Beenden und Neustarten keine Animationen ausgeführt werden.Nachdem nun die Grundlagen für das Verstehen von Hintergrundprozessen in Andro-id gelegt wurden, werden in den folgenden Kapiteln die Activities an sich behandelt.Den Anfang macht dabei die MainActivity.

5http://developer.android.com/reference/android/content/Intent.html

Sebastian Stallenberger Seite 34 von 104

Page 39: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

6.3 Activity MainActivityWie in Kapitel 5.1 dargestellt, stellt die MainActivity den Mittelpunkt von Spirit-Mobile dar. Sie beinhaltet das dynamische Hauptmenü, das je nach Rolle des einge-loggten Benutzers unterschiedliche Menü-Items anzeigt. Um die folgenden Kapitelvollständig verstehen zu können, ist es nützlich, den Lebenszyklus einer Android-Activity zu kennen. Abbildung 6.1 beschreibt diese Vorgänge in einer Activity.

Abbildung 6.1: Lebenszyklus einer Activity in Anlehnung an [Goo11a]

Laut [Goo11a] hat eine Activity vier Zustände:• Wenn sie im Vordergrund auf dem Bildschirm ist, ist sie „aktiv“ oder „laufend“.• Wenn sie den Fokus verloren hat, aber noch sichtbar ist, ist sie „pausiert“.

Eine pausierte Activity ist komplett am Leben, kann aber gewaltsam beendetwerden, wenn das System mehr Speicher benötigt.

• Eine komplett von einer anderen Anwendung verdeckte Activity ist „gestoppt“.Alle Zustands-Informationen bleiben erhalten, aber auch hier kann die Activitygewaltsam beendet werden, wenn Speichermangel herrscht.

• Nach dem Stoppen aufgrund von Speicherproblemen kann eine Activity wiederneu „gestartet“ und wiederhergestellt werden.

Nachdem nun die allgemeinen Abläufe in einer Activity bekannt sind, werden imFolgenden die onCreate- und onResume-Methoden der MainActivity betrachtet.

Sebastian Stallenberger Seite 35 von 104

Page 40: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

6.3.1 onCreate und onResume

Die onCreate-Methode enthält in der ersten Zeile den Methodenaufruf super.onCreate. Fehlt diese Zeile, gibt es beim Compilieren eine Fehlermeldung. Anschlie-ßend wird geprüft, ob die gesetzte Passphrase für die Closed Beta richtig eingegebenwurde. Ist dies der Fall, wird das normale Layout als ContentView, also als dasanzuzeigende Layout, gesetzt.

Listing 6.4: Die Methoden onCreate und onResume der MainActivityoverride def onCreate ( savedInstanceState : Bundle) {

super. onCreate ( savedInstanceState )

if ( SpiritHelpers . getStringPrefs ( MainActivity .this ," trialPassphrase ", false).equals(getString (R.string. trialPassphrase )))

{setContentView (R.layout. mainactivity )

} else {val mainlay = ViewBuilder . getTrialView (

MainActivity .this)setContentView ( mainlay )

}}

override def onResume () {super. onResume ()if ( SpiritHelpers . getStringPrefs ( MainActivity .this ,

" trialPassphrase ", false).equals(getString (R.string. trialPassphrase ))) {

buildMenu}

}

In der Methode onResume wird, wenn sich der Nutzer erfolgreich als Beta-Testerauthentifiziert hat, das Hauptmenü aufgebaut. Dies wird im Unterkapitel 6.3.3 er-läutert. Vorher nimmt sich der Autor in Kapitel 6.3.2 aber des Beta-Screens an,der dem Nutzer angezeigt wird, wenn er noch keine oder eine falsche Passphraseeingegeben hat.

6.3.2 Passphrase-Eingabe für die Beta

Der Beta-Screen ist ein Element, das nur in der Beta-Phase vorhanden ist. Es bestehtaus dem Spirit-Logo, einem EditText zur Eingabe der Passphrase und einem Button,um die Passphrase abzusenden.Will man Layouts in Android aufbauen, hat man zwei Möglichkeiten: Die eine führtüber sogenannte Adapter und externe XML-Files, die in den res/layout-Ordner aus-gelagert werden. Die andere ist, das Layout direkt im Code aufzubauen. Je nachSituation können beide Methoden beliebig vermischt werden. Der Beta-Screen wirdausschließlich per Code aufgebaut, da dieser nach Meinung des Autors nach Ablaufder Beta-Phase komfortabler zu entfernen ist. Der Aufbau findet in der Methode

Sebastian Stallenberger Seite 36 von 104

Page 41: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

ViewBuilder.getTrialView statt, welche ein RelativeLayout zurückliefert. Wie inden Listings 6.5, 6.6 und 6.7 zu sehen, kann die Methode in drei Abschnitte geglie-dert werden: das Anlegen und Konfigurieren der einzelnen Elemente, das Setzen derLayout-Attribute und den Zusammenbau des gesamten Layouts.

Listing 6.5: Der Code für den Aufbau des Beta-Screens (Teil 1)def getTrialView ( context: Context ): RelativeLayout = {

val activity = context . asInstanceOf [ Activity ]val mainlay = new RelativeLayout ( context ) {

val id_logo = 2020201[...]val id_button = 2020204

val logo = new ImageView ( context ) {setImageDrawable ( getResources . getDrawable (

R. drawable .logo_spirit_transp))setAdjustViewBounds (true)setPadding (0, 20, 0, 30)setId(id_logo)

}

val tv = new TextView ( context ) {setText ("Beta Passphrase ")setId(id_text)

}

val edit = new EditText ( context ) {setMinimumWidth (200)setId(id_edit)

}

val button = new Button( context ) {setText ("Unlock")setId(id_button)setOnClickListener (new OnClickListener {

def onClick (p1: View) {SpiritHelpers . setPrefs (activity ,

" trialPassphrase ",edit. getText .toString , false)

var intent: Intent = activity . getIntentactivity .finishactivity . overridePendingTransition (0, 0)activity . startActivity (intent)

}})

}

Zu Beginn werden beliebig gewählte Integer-Werte als Ids für die Elemente fest-gesetzt. Danach folgt das Logo, das in eine ImageView gebettet ist. Als Ressourcedafür dient das Drawable logo_spirit_transp, das im Verzeichnis res/drawableabgelegt ist. Das Logo ist eigentlich größer als der Bildschirm, wird aber passend,mit gleichbleibendem Seitenverhältnis, skaliert. Doch auch mit der Skalierung wür-

Sebastian Stallenberger Seite 37 von 104

Page 42: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

de normalerweise Platz für die Originalgröße des Bilds reserviert werden und somitden folgenden Inhalt unschön vertikal verschieben. Um das zu vermeiden, ist dasAttribut setAdjustViewBounds auf true gesetzt. Mit setPadding kann dann dergewünschte innere Abstand6 der View Links, Oben, Rechts und Unten gesetzt wer-den. Letztendlich setzt setId die Id des Elements.Für die TextView werden die Attribute Text und Id gesetzt. Gleich darauf folgendfür das EditText die minimale Breite und die Id.Beim Button wird neben dem Text erstmals ein onClickListener gesetzt. Bei einemKlick auf den Button wird zum einen die Funktion SpiritHelpers.setStringPrefsaufgerufen und zum anderen die aktuelle Activity neu gestartet. Auf die MethodeSpiritHelpers.setStringPrefs wird im Kapitel 6.9 genauer eingegangen.

Listing 6.6: Der Code für den Aufbau des Beta-Screens (Teil 2)var lp_iv = new RelativeLayout .

LayoutParams (-2,-2). asInstanceOf [RelativeLayout . LayoutParams ]

lp_iv. addRule ( RelativeLayout .CENTER_HORIZONTAL )lp_iv. addRule ( RelativeLayout .ALIGN_PARENT_TOP)

var lp_tv = new RelativeLayout .LayoutParams (-2,-2). asInstanceOf [

RelativeLayout . LayoutParams ]lp_tv. addRule ( RelativeLayout .BELOW , id_logo)lp_tv. addRule ( RelativeLayout .CENTER_HORIZONTAL )

var lp_edit= new RelativeLayout .LayoutParams (-2,-2). asInstanceOf [

RelativeLayout . LayoutParams ]lp_edit. addRule ( RelativeLayout .BELOW , id_text)lp_edit. addRule ( RelativeLayout .CENTER_HORIZONTAL )

var lp_button=new RelativeLayout .LayoutParams (-2,-2). asInstanceOf [

RelativeLayout . LayoutParams ]lp_button. addRule ( RelativeLayout .BELOW , id_edit)lp_button. addRule ( RelativeLayout .CENTER_HORIZONTAL )

Der zweite Abschnitt der Methode enthält Regeln für den Aufbau des RelativeLay-outs. Hier kann angegeben werden, welches Element sich abhängig von den anderenElementen oder vom Eltern-Element wo im Aufbau befinden soll. Die -2 in denLayoutParams steht für WRAP_CONTENT, was bedeutet, dass das Element nur so großist, wie sein Inhalt. Eine andere Option wäre FILL_PARENT7(als Int: -1), was danndie gesamte Bildschirm-Höhe bzw. -Breite ausfüllt.

6also dem Abstand zwischen dem Inhalt und den äußeren Rändern7in API Level 8 und höher wurde dies in MATCH_PARENT umbenannt

Sebastian Stallenberger Seite 38 von 104

Page 43: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Listing 6.7: Der Code für den Aufbau des Beta-Screens (Teil 3)addView (logo , lp_iv)addView (tv , lp_tv)addView (edit , lp_edit)addView (button , lp_button)

}mainlay

}

Im dritten Abschnitt werden die einzelnen Elemente zum RelativeLayout hinzuge-fügt und das Layout wird zurückgegeben. Nach dem Aufbau des Beta-Screens gehtder Autor auf den des Hauptmenüs ein.

6.3.3 Hauptmenü

Das Hauptmenü sollte in seiner Implementierung sollte so gestaltet sein, dass es mög-lichst einfach und dynamisch erweiterbar ist. Der Autor hat sich für eine GridViewin Kombination mit einem BaseAdapter8 entschieden, da dieser durch das AndroidSDK schon bereitgestellt wird und genau die gewünschte Funktionalität bietet. DasMenü wird in der Methode buildMenu aufgebaut.

Listing 6.8: Die Abfrage der Rolle und die Definition des Menü-Arrays.val role = SpiritHelpers . getStringPrefs (

MainActivity .this , "role", false)val dataList = role match {

case " professor " =>List(new MenuEntry (R. drawable .menu_news_bs ,

getString (R.string.menu_news), " readNews ", true),new MenuEntry (R. drawable .menu_writenews_bs ,

getString (R.string.menu_createNews ), " writeNews ",true),

new MenuEntry (R. drawable .menu_timetable_bs ,getString (R.string.menu_timetable ), " timeTable ",

false))case " student " =>

List(new MenuEntry (R. drawable .menu_news_bs ,getString (R.string.menu_news), " readNews ", true),

new MenuEntry (R. drawable .menu_timetable_bs ,getString (R.string.menu_timetable ), " timeTable ",

false))case _ =>

List(new MenuEntry (R. drawable .menu_news_bs ,getString (R.string.menu_news), " readNews ", true))

}

Zu Beginn wird die Rolle des aktuell eingeloggten Nutzers über die Methode SpiritHelpers.getStringPrefs9 abgefragt. Der Inhalt des eigentlichen Menüs wird in ei-ner Liste von MenuEntry-Elementen definiert. Ein MenuEntry-Element enthält dabei

8Vgl. http://developer.android.com/resources/tutorials/views/hello-gridview.html9Wird in Kapitel 6.9 erläutert.

Sebastian Stallenberger Seite 39 von 104

Page 44: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

jeweils die Drawable-Id, den Text, einen String, der die beim Klick auszuführendeAktion beschreibt und einen Boolean-Wert, der definiert, ob das Element aktiv oderinaktiv ist.Abhängig von der abgefragten Rolle wird dataList mit verschiedenen Listen undsomit das Menü nach dem Aufbau mit verschiedenen Elementen gefüllt. Über dieMethode findViewById holt man sich die GridView aus dem externen XML-Layout.Über setAdapter wird der in Listing 6.11 definierte Adapter der GridView zuge-wiesen. In Listing 6.9 wird außerdem das onClick-Ereignis der einzelnen Elementeabgefangen.

Listing 6.9: Die Verbindung zwischen dataList und der GridView.val grid = findViewById (R.id.grid). asInstanceOf [ GridView ]grid. setAdapter (new MainMenuAdapter ( MainActivity .this ,

dataList ))grid. setOnItemClickListener (

new OnItemClickListener {def onItemClick (parent: AdapterView [_], p2: View ,

itemId: Int , p4: Long) {val clickedItem = parent. getItemAtPosition (

itemId). asInstanceOf [ MenuEntry ]

if (! clickedItem . enabled ) {Toast. makeText ( MainActivity .this ,getString (R.string.err_ notImplementedYet ),

Toast.LENGTH_SHORT).show ()} else {

menuHandler ( MainActivity .this ,clickedItem . functionName )

}}

})

Ist ein Item aktiv, wird der menuHandler (Listing 6.10) angewiesen, die in dataListfür dieses Element definierte Funktion auszuführen. TimeTable ist in der prototy-pischen Implementation noch nicht vorhanden, weshalb auch die Methode dafür immenuHandler fehlt.

Listing 6.10: Die Methode menuHandler.def menuHandler ( context: Context , functionName : String) {

functionName match {case " readNews " =>

val intent = new Intent(context ,classOf [ NewsMulti ])

intent. putExtra ("load", true)context . startActivity (intent)

case " writeNews " => startActivity (new Intent(this , classOf [ NewsCreate ]))

}}

Sebastian Stallenberger Seite 40 von 104

Page 45: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Wie schon geschrieben, erweitert der MainMenuAdapter den BaseAdapter. Zu Beginnwerden erforderliche Methoden implementiert, die für den Zugriff des Adapters aufdie Liste dataList nötig sind.

Listing 6.11: Der MainMenuAdapter.class MainMenuAdapter ( context: Context , menuItems: List[

MenuEntry ]) extends BaseAdapter {override def getCount: Int = {

menuItems .size}

override def getItem ( position: Int): Object = {menuItems ( position )

}

override def getItemId ( position: Int): Long = {position

}

override def getView ( position: Int , convertView :View ,parent: ViewGroup ): View = {

var mev: MenuEntryView = null

if ( convertView == null) {mev = new MenuEntryView (context ,

menuItems ( position ))} else {

mev = convertView . asInstanceOf [ MenuEntryView ]}

mev}

}

In der Klasse MenuEntryView werden der Aufbau und das Design der einzelnenMenü-Elemente festgelegt. In Listing 6.11 sind allerdings nur die neuen und rele-vanten Elemente von MenuEntryView zu sehen, da der Rest jedem anderen Layout-Aufbau per Code ähnelt. Das MenuEntryView basiert erneut auf einem RelativeLay-out.Nach dem Erzeugen der ImageView und der TextView werden die Drawables fürden Hintergrund und das Menü-Element-Icon geladen. Nachdem der Alpha-Wert desHintergrunds auf 60% gesetzt wurde, wird die Farbe der TextView auf „SpiritWhite“gesetzt, das vorher in einer externen XML-Datei definiert wurde.Wirklich interessant ist der mittlere Teil des Listings 6.12, in dem ein ColorFilter10

für die Drawables gesetzt wird. Laut [Guy09] haben Drawables derselben Ressource,die an verschiedenen Stellen im Code geladen werden, einen sogenannten „Constantstate“. Ändert man zum Beispiel den Alpha-Wert eines Drawables an Stelle 1, ist abdiesem Zeitpunkt der Alpha-Wert auch für das Drawable an Stelle 2 und 3 gesetzt.

10Vgl. http://developer.android.com/reference/android/graphics/ColorFilter.html

Sebastian Stallenberger Seite 41 von 104

Page 46: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Listing 6.12: Auszüge aus der Klasse MainMenuAdapter.[...]var iv: ImageView = new ImageView ( context )var tv: TextView = new TextView ( context )var iconDraw = getResources . getDrawable (

menuEntry . drawableId )var menuItemBackground = getResources . getDrawable (

R. drawable . optmenubg )

menuItemBackground . setAlpha (60)tv. setTextColor ( getResources .

getColor (R.color. SpiritWhite ))

if (! menuEntry . enabled ) {menuItemBackground .mutate (). setColorFilter (

0x77000000 , Mode.SRC_ATOP)iconDraw .mutate (). setColorFilter (

0x77000000 , Mode.SRC_ATOP)iconDraw .mutate (). setAlpha (50)tv. setTextColor ( getResources . getColor (

R.color. SpiritLightBlue ))}

setBackgroundDrawable ( menuItemBackground )iv. setImageDrawable ( iconDraw )[...]

Für unser Menü heißt das, wenn Menü-Element 1 deaktiviert ist und damit das Dra-wable des Hintergrunds einen ColorFilter bekommt und sein Alpha-Wert auf 50%gesetzt wird, dann sind diese Änderungen auch für die Hintergründe der anderenMenü-Elemente gesetzt. Abhilfe schafft die Drawable-Methode mutate. Dadurch be-kommt jedes Drawable aus der gleichen Ressource einen anderen „Constant state“und damit auch seinen eigenen Farbfilter und Alpha-Wert.Im nächsten Abschnitt wird das Android „Options menu“ betrachtet, das an einigenStellen in SpiritMobile eingesetzt wird.

6.3.4 Options menu

Das sogenannte „Options menu“11 ist das Menü in Android, das sich öffnet, wennder Nutzer die Menü-Taste seines Geräts drückt. Dieses Menü muss für jede Activity,in der es auftauchen soll, neu definiert werden. In Abbildung 6.2 kann man sehen,wie das fertig aufgebaute Menü mit geöffnetem Optionsmenü für einen Professoraussieht.Das Optionsmenü ist in diesem Fall aus drei Teilen aufgebaut. Der erste Teil ist dieFunktion onCreateOptionsMenu und ist dafür verantwortlich was passiert, wenn die„Menu“-Taste des Geräts gedrückt wird. Der MenuInflater baut das Menü aus denDaten auf, die er aus der in res/menu liegenden options.xml-Datei bekommt.

11im Folgenden Optionsmenü genannt

Sebastian Stallenberger Seite 42 von 104

Page 47: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Abbildung 6.2: Screenshot der Activity MainActivity mit geöffnetem Optionsmenü

Listing 6.13: Der Aufbau eines Optionsmenü (Teil 1)override def onCreateOptionsMenu (menu: Menu) = {

val inflater: MenuInflater = getMenuInflaterinflater . inflate (R.menu.options , menu)true

}

Diese Datei options.xml ist der zweite Teil. Das Root-Element ist der menu-Tag.Für jedes Element, das im Menü angezeigt werden soll, wird ein item-Tag angelegt.Dieser enthält die Informationen id, icon und title.

Listing 6.14: Der Aufbau eines Optionsmenü (Teil 2)<?xml version="1.0" encoding="utf -8"?>

<menu xmlns:android="http:// schemas . android .com/apk/res/android ">

<item android:id="@+id/ userdata "android:icon="@drawable / optmenuuser _l"android:title=" Einstellungen " />

<item android:id="@+id/help"android:icon="@drawable / optmenuhelp _l"android:title="Hilfe" />

</menu >

Der dritte Teil ist die Methode onOptionsItemSelected, die bestimmt, was ge-schieht, wenn auf die einzelnen Elemente des Menüs geklickt wird.

Sebastian Stallenberger Seite 43 von 104

Page 48: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Listing 6.15: Der Aufbau eines Optionsmenü (Teil 3)override def onOptionsItemSelected (item: MenuItem ) = {

item. getItemId match {case R.id. userdata =>

val optUserDataIntent = new Intent(this ,classOf [ Settings ])

startActivity ( optUserDataIntent )true

case R.id.help =>val optInfoIntent = new Intent(this , classOf [Info ])startActivity ( optInfoIntent )true

case _ => super. onOptionsItemSelected (item)}

}

So wird anhand der Id das Event zugewiesen und entweder die Settings- oder die Info-Activity gestartet. Das waren die wichtigsten Elemente der Activity MainActivity.Im Kapitel 6.4 wird nun die Activity NewsMulti vorgestellt.

6.4 Activity NewsMultiWie in Kapitel 5.2 schon erläutert, ist NewsMulti für die Auflistung der News zu-ständig. In onCreate (Listing 6.16) überprüft die Applikation mit der in Listing 6.17dargestellten Methode SpiritConnect.checkInternetConnection, ob eine Inter-netverbindung vorhanden ist. Dabei ist es unwichtig, ob die Verbindung per WLANoder UMTS aufgebaut wurde.

Listing 6.16: Inhalt der onCreate-Methode von NewsMultiif ( SpiritConnect . checkInternetConnection (this)) {

new NewsReloadTask ( NewsMulti .this). execute (null)} else {

Toast. makeText ( NewsMulti .this ,getString (R.string.err_noInternet ),

Toast.LENGTH_LONG).show ()ViewBuilder . constructNewsMultiMainLay ( NewsMulti .this)

}

Ist keine Internet-Verbindung vorhanden, wird dies dem Nutzer durch einen Toastangezeigt und die Liste der News mit alten Daten aufgebaut, wenn vorhanden.Hat das Gerät Verbindung zum Internet, wird der Task NewsReloadTask durch seineMethode execute ausgeführt. Der Methode execute muss an dieser Stelle unbedingtetwas12 übergeben werden, da sonst eine RuntimeException in AsyncTask auftritt.In NewsReloadTask werden im Hintergrund die beiden Methoden SpiritConnect.getNews und SpiritConnect.getDegreeClasses, die im Kapitel 6.9 genauer be-trachtet werden, ausgeführt. Nach deren Abschluss wird das Layout mit der Metho-

12Auch, wenn es nur „null“ ist.

Sebastian Stallenberger Seite 44 von 104

Page 49: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

de ViewBuilder.constructNewsMultiMainLay, welche in Listing 6.18 zu sehen ist,aufgebaut. Allerdings diesmal mit aktuellen Daten.

Listing 6.17: Die Methode checkInternetConnection in SpiritConnectdef checkInternetConnection ( context: Context ):Boolean = {

val connectivityManager = context . getSystemService (Context . CONNECTIVITY _SERVICE ).

asInstanceOf [ ConnectivityManager ]

if ( connectivityManager .getActiveNetworkInfo != null

&& connectivityManager .getActiveNetworkInfo . isAvailable

&& connectivityManager .getActiveNetworkInfo . isConnected ) {

true} else {

false}

}

6.4.1 Konstruktion der News-Liste

Listing 6.18: Die Methode constructNewsMultiMainLay in ViewBuilderdef constructNewsMultiMainLay ( context: Context ) {

val activity = context . asInstanceOf [ Activity ]activity . setContentView (R.layout. newsmulti )val lastNewsDateTV = activity . findViewById (

R.id. lastNewsDate ). asInstanceOf [ TextView ]val newsMainLinLay = activity . findViewById (

R.id. newsMain ). asInstanceOf [ LinearLayout ]

val loadedJsonString = SpiritHelpers .loadString (activity , " newsJsonString ")

val newsList = JsonProcessor .jsonStringToNewsList ( loadedJsonString ).

asInstanceOf [List[News ]]

lastNewsDateTV . setText ( activity . getString (R.string.string_ lastNewsFetch ) +

SpiritHelpers . getStringPrefs (activity ," LastNewsDate ", false))

newsList . foreach (element => {

newsMainLinLay . addView (ViewBuilder . buildNewsView (context ,

element . asInstanceOf [News ]))newsMainLinLay . addView (new FrameLayout (

context ) {setMinimumHeight (12)

})})}

Sebastian Stallenberger Seite 45 von 104

Page 50: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Nach dem Laden des XML-Basis-Layouts (res/layout/newsmulti.xml) mit der Text-View für die Anzeige des letzten Updates und des LinearLayouts als Containerfür die News wird der vorher gespeicherte News-JSON-String mittels der Metho-de SpiritHelpers.loadString geladen. Dieser JSON-String wird anschließend andie Funktion JsonProcessor.jsonStringToNewsList übergeben, welche ein List[News]-Objekt zurückliefert. Beide Methoden werden im Kapitel 6.9 erklärt.Das Feld des letzten Updates wird mit dem Datum aus den Preferences gefüttert,welches im Vorgang des News-Updates gesetzt wurde. Letztendlich wird aus demList[News]-Objekt über eine foreach-Schleife die Liste der News aufgebaut. Dasich an dieser Stelle kein Margin oder Padding setzen ließ, wurde als Platzhalterzwischen den News jeweils ein FrameLayout mit einer festen Höhe eingefügt.

6.4.2 Aufbau einer einzelnen News

Eine einzelne View für eine News wird in ViewBuilder.buildNewsView zusammen-gebaut. Da diese Funktion sehr umfangreich ist und die Konstruktion von Viewsin den vorgehenden Kapiteln schon behandelt wurde, werden an dieser Stelle nurAuszüge der wichtigsten Teile daraus vorgestellt.

Listing 6.19: Die Konstruktion einer einzelnen News in der Funktion ViewBuil-der.buildNewsView (Teil 1)

def buildNewsView ( context: Context , news: News):RelativeLayout = {

val activity = context . asInstanceOf [ Activity ]val fill_parent = -1val wrap_content = -2val idbase = 19830615val id_title = idbase + 1[...]val id_ degreeclass = idbase + 7

val newsRelativeLayout = new RelativeLayout ( context ) {var degreeclassbackground = this. getResources .

getDrawable (R. drawable . newsbackgroundheader )

var newsbackgroundheader = this. getResources .getDrawable (R. drawable . newsbackgroundheader )

var footerbackground = this. getResources .getDrawable (R. drawable . newsbackgroundheader )

var newsbackgroundsmall2 = this. getResources .getDrawable (R. drawable . newsbackgroundsmall2 )

Nachdem die Ids für alle Elemente gesetzt und die Hintergrundbilder geladen wurden(Listing 6.19), wird abgefragt, ob der aktuell eingeloggte Nutzer mit dem Eigentümer(owner) der News übereinstimmt. Ist dies der Fall, wird zu Beginn von Listing 6.20ein ColorFilter für die Kopfzeile (header) gesetzt.

Sebastian Stallenberger Seite 46 von 104

Page 51: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Listing 6.20: Die Konstruktion einer einzelnen News in der Funktion ViewBuil-der.buildNewsView (Teil 2)

if ( SpiritHelpers . getStringPrefs (activity ," editFhsId ", false).equals(news.owner.fhs_id)) {

val filterColor = Color.rgb (199 , 21, 133)newsbackgroundheader .mutate (). setColorFilter (

filterColor , Mode. MULTIPLY )}

val headerRelativeLayout = new RelativeLayout ([...]) {val titleTextView = new TextView ( context ) {

setText (news.title)

setTextAppearance (context ,android .R.style. TextAppearance _Medium)

[...]setLines (1)[...]val ta: TruncateAt = TruncateAt .ENDsetEllipsize (ta)

}

[...]

setBackgroundDrawable ( newsbackgroundheader )setId(id_header)

addView ( titleTextView )addView ( dateTextView )

}

Anschließend wird der Text des Titels festgelegt und die Textgröße eingestellt. Dadie News in der News-Liste ja möglichst kompakt angezeigt werden sollen, wird dieHöhe der Header-Zeile auf maximal eine Zeile festgelegt. Sollte der Titel zu lang fürdiese Zeile sein, wird er per setEllipsize gekürzt und mit drei Punkten beendet.Die restlichen Elemente werden ebenfalls entsprechend gefüllt, konfiguriert und inListing 6.21 zu der View der News hinzugefügt.Am Ende der Methode werden die zwei Events onClickListener und onLongClickListener abgefangen. Der Inhalt der onClickListeners ist im folgenden Kapi-tel 6.5 im Listing 6.23 zu sehen. Bei einem langen Klick auf eine News wird deronLongClickListener ausgelöst. An dieser Stelle ist bei SpiritMobile aktuell nochnichts implementiert. Angedacht ist, dem Nutzer zu ermöglichen, mit einem langenKlick seine eigene News zu editieren oder zu löschen. Aktuell wird dem Nutzer nurein Toast anstelle dieser Funktionen angezeigt.In der Activity NewsMulti wird erstmals die Methode onActivityResult behan-delt. Wann diese ausgelöst wird und was sie bewirkt, wird im folgenden Abschnitterläutert.

Sebastian Stallenberger Seite 47 von 104

Page 52: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Listing 6.21: Die Konstruktion einer einzelnen News in der Funktion ViewBuil-der.buildNewsView (Teil 3)

addView ( headerRelativeLayout )addView ( degreeclassTextView )addView ( contentTextView )addView ( footerRelativeLayout )

[...]

setOnClickListener (new View. OnClickListener () {override def onClick (v: View) {

[...]}}

[...]

if ( SpiritHelpers . getStringPrefs (activity ," editFhsId ", false).equals(news.owner.fhs_id)) {

setOnLongClickListener (new OnLongClickListener {def onLongClick (p1: View) = {

Toast. makeText (context , "DELETE",Toast.LENGTH_LONG).show ()

true}}) }}

newsRelativeLayout}

6.4.3 onActivityResult

Wenn in NewsSingle ein neuer Kommentar eingetragen wurde, muss sich auch dieAnzahl der in NewsMulti angezeigten Kommentare der entsprechenden News än-dern. Das könnte man über die onResume-Methode lösen. Dann würde allerdingsimmer, wenn der Nutzer zu NewsMulti zurück navigiert, ein Reload ausgelöst wer-den. Da dies nicht nur unnötig ist, sondern auch sehr störend für den Nutzer seinkann, wurde das Problem anders gelöst.

Listing 6.22: Die Methode onActivityResult in NewsMultioverride def onActivityResult ( requestCode : Int ,

resultCode: Int , data: Intent) {super. onActivityResult (requestCode , resultCode , data)

val extras = data. getExtrasif (extras != null) {

if (extras. containsKey (" newSingleNews ")) {[...]

}}

}

Sebastian Stallenberger Seite 48 von 104

Page 53: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Über die Methode onActivityResult kann auf ein Ergebnis aus NewsSingle reagiertwerden, weil NewsSingle aus NewsMulti nicht mit dem normalen startActivitygestartet wird sondern mit startActivityForResult13. Das Ergebnis „newSingle-News“ wird in NewsSingle dann gesetzt, wenn ein neuer Kommentar angelegt wurde.Der große Vorteil ist also nun, dass der Reload bei der Rückkehr von NewsSinglenur ausgelöst wird, wenn auch ein neuer Kommentar angelegt wurde.Wie das genau funktioniert, wird jetzt im folgenden Kapitel 6.5 noch genauer erklärt.

6.5 Activity NewsSingleUm die Vorgänge in diesem Abschnitt besser verstehen zu können, wird kurz erklärt,was ein Intent in Android ist. Laut [Goo11f] ist ein Intent eine abstrakte Beschrei-bung einer auszuführenden Operation. Er beschreibt also die Absicht, etwas zu tun.Genutzt werden kann ein Intent dazu, eine Activity zu starten oder mit Broadca-stRecievern oder Services zu kommunizieren. In SpiritMobile werden Intents bisherausschließlich zum Starten von Activities genutzt. Hier unterscheidet man, ob vonder gestarteten Activity ein Ergebnis erwartet wird oder nicht.

Listing 6.23: Der Inhalt des onClick-Events einer News in NewsMultival newsIntent = new Intent(context , classOf [ NewsSingle ])newsIntent . putExtra (" singleNewsJson ", news)activity . startActivityForResult (newsIntent , 198300)

Die bisher betrachteten Activities wurden ausschließlich ohne Ergebnis gestartet(z.B. in Listing 6.15 oder 6.10). Startet man von NewsMulti aus eine NewsSingle-Activity, wird diese statt bisher mit startActivity mit startActivityForResultaufgerufen. In Listing 6.23 sieht man die konkrete Verwendung in NewsMulti. Dasnews-Objekt wird dem Intent als Extra „singleNewsJson“ übergeben und anschlie-ßend wird die Activity mit Erwartung auf ein Ergebnis gestartet.In NewsSingle wird ausschließlich die Methode onCreate aufgerufen. Die News, dieangezeigt werden soll, kann aus zwei veschiedenen Quellen stammen:

• Sie wurde beim Start der Activity in NewsMulti mit übergeben und ist in denExtras unter dem Schlüssel „singleNewsJson“ abgelegt.

• Es wurde ein neuer Kommentar angelegt und die News daraufhin einzeln abge-rufen. In diesem Fall verbirgt sich die News hinter dem Schlüssel „newSingle-News“.

Der Schlüssel „newSingleNews“ hat eine höhere Priorität als „singleNewsJson“. Istalso eine News in „newSingleJson“ vorhanden, wird diese angezeigt.Nachdem die Quelle für die anzuzeigende News festgelegt wurde, wird mit Actitivy.RESULT_OK über die Methode setResult der Status des Ergebnisses gesetzt. Diessignalisiert nach der Rückkehr in NewsMulti, dass das Ergebnis in NewsSingle ord-nungsgemäß gesetzt wurde. Dies geschieht unabhängig davon, ob überhaupt einInhalt in „newSingleNews“ vorhanden ist.13Darauf wird in Kapitel 6.5 näher eingegangen.

Sebastian Stallenberger Seite 49 von 104

Page 54: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Listing 6.24: Die Activity NewsSingleclass NewsSingle extends Activity {

var text: StringBuilder = new StringBuilder ()

override def onCreate ( savedInstanceState : Bundle) {super. onCreate ( savedInstanceState )setContentView (R.layout. newssingle )val intent = getIntentval extras: Bundle = intent. getExtras ()

. asInstanceOf [Bundle]

if (extras == null) {Toast. makeText ( NewsSingle .this ,

getString (R.string.err_ erroroccured ),Toast.LENGTH_LONG).show ()

} else {val news = if (extras. containsKey (" newSingleNews ")){

extras.get(" newSingleNews "). asInstanceOf [News]} else {

extras.get(" singleNewsJson "). asInstanceOf [News]}

setResult ( Activity .RESULT_OK , intent)

val newsMain = findViewById (R.id. newsSingleMain ).asInstanceOf [ LinearLayout ]

newsMain . setOrientation ( LinearLayout . VERTICAL )newsMain . addView ( ViewBuilder .

buildNewsViewSingle ( NewsSingle .this , news))

val commList = news. newsComment .toList.asInstanceOf [List[ NewsComment ]]

newsMain . addView ( ViewBuilder . buildCommentsView (NewsSingle .this , commList , news.news_id))

}}

}

Der Aufbau der News ist dem einer einzelnen News in NewsMulti sehr ähnlich. Al-lerdings ist hier weder der Inhalt des Titels noch der des Inhalts auf eine bestimmteZeilenanzahl begrenzt. Man kann in dieser Ansicht also uneingeschränkt die kom-plette News lesen.Der Aufbau der Kommentar-Liste erfolgt in ViewBuilder.buildCommentsView. DerMethode wird eine List[NewsComment] übergeben und mithilfe der Methode singleCommentView wird über eine Schleife die Liste der Kommentare als Layout konstru-iert.Der Bereich zum Anlegen neuer Kommentare befindet sich direkt unter der Kom-mentar-Liste. Über die Abfrage in Listing 6.27 wird gesichert, dass nur Nutzer mitder Rolle „professor“ oder „student“ diesen Bereich angezeigt bekommen. Der Be-reich an sich besteht aus einem EditText und einem Button.

Sebastian Stallenberger Seite 50 von 104

Page 55: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Listing 6.25: Die Methode buildCommentsView zur Konstruktion der Kommentar-Liste. (Teil 1)

def buildCommentsView ( context: Context , commentList :List[ NewsComment ], newsId: Int): LinearLayout = {

[...]commentList . foreach (

element => linLay. addView (singleCommentView (context , element ))

)

Listing 6.26: Die Methode buildCommentsView zur Konstruktion der Kommentar-Liste. (Teil 2)

val newCommentView = new RelativeLayout ( context ) {val newCommEdit : EditText = new EditText ( context ) {

[...]setOnClickListener (new View. OnClickListener () {

override def onClick (v: View) {newCommButton . setVisibility (View. VISIBLE )

}})}val newCommButton = new Button( context ) {

[...]setVisibility (View.GONE)

setOnClickListener (new View. OnClickListener () {override def onClick (v: View) {

if ( newCommEdit . getText . toString .equals("")) {Toast. makeText (context ,

R.string.string_commess_must ,Toast.LENGTH_SHORT).show ()

} else {val fhsId = SpiritHelpers . getStringPrefs (

context . asInstanceOf [ Activity ]," editFhsId ", false)

new NewsCommentCreateTask ( context ). execute (Array(newsId.toString , fhsId ,newCommEdit . getText . toString ))

}}})}[...]

}

Der Button ist zu Beginn allerdings noch nicht zu sehen und wird erst eingeblendet,wenn der Nutzer in das EditText klickt. Erreicht werden kann das über die AttributeVisibility, die mit der Methode setVisibility wahlweise auf View.VISIBLE oderView.GONE gesetzt werden.Wird der Button gedrückt und das EditText hat keinen Inhalt, wird das dem Nutzerüber einen Toast signalisiert. Hat das EditText Inhalt, wird dieser zusammen mitder newsId und der fhsId des Nutzers an den Task NewsCommentCreateTask über-geben. In dessen doInBackground-Methode werden diese Parameter an die MethodeSpiritConnect.createNewsComment weitergegeben.

Sebastian Stallenberger Seite 51 von 104

Page 56: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Listing 6.27: Die Methode buildCommentsView zur Konstruktion der Kommentar-Liste. (Teil 3)

val role = SpiritHelpers . getStringPrefs ( context .asInstanceOf [ Activity ], "role", false)

if (role.equals(" student ") || role.equals(" professor ")) {linLay. addView ( newCommentView )

}[...]}

Listing 6.28: Auszüge aus dem Task NewsCommentCreateTask.class NewsCommentCreateTask ( context: Context ) extends

AsyncTaskAdapter [Array[String], Unit , Boolean ] {[...]override protected def doInBackground (

params: Array[String ]): Boolean = {newsId = params (0).toIntSpiritConnect . createNewsComment (context , newsId ,

params (1) , params (2))}

override protected def onPostExecute ( success: Boolean ):Unit = {

[...]if ( success ) {

Toast. makeText (context , " Kommentar erfolgreicheingetragen !", Toast.LENGTH_LONG).show

new NewsLoadSingleTask ( context ). execute (newsId. toString )

}else {

Toast. makeText (context , "Fehler beim Eintragen desKommentars !", Toast.LENGTH_LONG).show

}}[...]}

Der Rückgabewert der Methode createNewsComment ist ein Boolescher Wert. Istdieser true, war das Eintragen des Kommentars erfolgreich. Dies wird dem Nutzerdurch einen Toast angezeigt und der Task NewsLoadSingleTask wird mit der newsIdausgeführt. Ist der Rückgabewert false, wird das dem Nutzer ebenfalls in einemToast gezeigt und er hat die Möglichkeit, seine Eingabe zu verbessern oder es nocheinmal zu probieren.

Listing 6.29: Auszüge aus dem Task NewsLoadSingleTask.class NewsLoadSingleTask ( context: Context ) extends

AsyncTaskAdapter [String , Unit , News] { [...]override protected def onPostExecute (param: News) {

[...]intent. putExtra (" newSingleNews ", param)

[...]}

Sebastian Stallenberger Seite 52 von 104

Page 57: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Die durch getSingleNews empfangene News wird als Extra unter dem Schlüssel„newSingleNews“ gesetzt und anschließend wird die Activity NewsSingle mit deraktuellen News neu gestartet.In den vorhergehenden Kapiteln wurde behandelt, wie der Aufbau der Activities,die für die News-Anzeige verantwortlich sind, gelöst wurde. Im folgenden Kapiteldreht sich nun alles um die Activity NewsCreate, über die eine neue News angelegtwerden kann.

6.6 Activity NewsCreateDie Activity NewsCreate ist im Layout sehr statisch. Dynamische Elemente sindnicht enthalten. Das Layout ist komplett in der XML-Datei newscreate.xml definiert,die man in Listing 6.30 sehen kann. Alle in diesem Kapitel erwähnten Methoden ausden Klassen JsonProcessor und SpiritHelpers werden im Kapitel 6.9 näher erläutert.

Listing 6.30: Die Datei newscreate.xml mit dem Layout für die Activity NewsCreate.<?xml version="1.0" encoding="utf -8"?><RelativeLayout xmlns:android="http:// schemas . android ..."

android:layout_width="fill_parent"android:layout_height="fill_parent">

<RelativeLayout android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="@drawable / newsbackgroundsmall2 "android:layout_ alignParentTop ="true"android:layout_ centerHorizontal ="true"android:layout_above="@+id/ createButton "android:layout_ marginBottom ="5dip"android:layout_marginTop="5dip"android:layout_marginLeft="2dip"android:layout_ marginRight ="2dip">

<TextView android:text=" Betreff:"android:layout_height="wrap_content "android:layout_ alignParentTop ="true"android:layout_width="fill_parent"android:layout_ centerHorizontal ="true"android:id="@+id/ tvSubject "/>

<EditText android:layout_width="fill_parent"android:layout_height="wrap_content "android:layout_below="@+id/ tvSubject "android:layout_alignLeft="@+id/ tvSubject "android:layout_alignRight="@+id/ tvSubject "android:id="@+id/ editSubject "/>

<TextView android:text=" Nachricht:"android:layout_height="wrap_content "android:layout_width="fill_parent"android:layout_ centerHorizontal ="true"android:layout_below="@+id/ editSubject "android:layout_alignLeft="@+id/ editSubject "android:layout_alignRight="@+id/ editSubject "android:id="@+id/ tvMessage "/>

Sebastian Stallenberger Seite 53 von 104

Page 58: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

<EditText android:layout_width="fill_parent"android:inputType=" textMultiLine "android:layout_height="wrap_content "android:minLines="5"android:layout_below="@+id/ tvMessage "android:layout_alignLeft="@+id/ tvMessage "android:layout_alignRight="@+id/ tvMessage "android:id="@+id/ editMessage "android:gravity="top"android:layout_above="@+id/ degreeText "/>

<TextView android:text=" Betrifft:"android:layout_height="wrap_content "android:layout_width="fill_parent"android:id="@+id/ degreeText "android:layout_above="@+id/ datePexpiredegreeText "android:background=

"@drawable / newsbackgroundsmall2 "/><TextView android:text=" Gueltig bis: "

android:layout_height="wrap_content "android:layout_width="fill_parent"android:id="@+id/ datePexpiredegreeText "android:layout_ alignParentBottom ="true"android:background=

"@drawable / newsbackgroundsmall2 "/></ RelativeLayout ><Button android:id="@+id/ createButton "

android:layout_height="wrap_content "android:layout_width="fill_parent"android:text="Senden"android:layout_ alignParentBottom ="true"/>

</ RelativeLayout >

Wie im Kapitel 5.4 beschrieben, kann der Nutzer sowohl Betreff und Nachrichteingeben als auch die betroffenen DegreeClasses und das Ablaufdatum festsetzen.Das vertikal in der Größe veränderbare Element ist im Aufbau das EditText für dieNachricht.Am Anfang der Activity NewsCreate werden Ids für die Dialoge vergeben und leereArrays angelegt, die zum Befüllen des DegreeClass-Dialogs nötig sind.

Listing 6.31: Auszug aus der Activity NewsCreate.class NewsCreate extends Activity {

val DEGREEDIALOGID = 0val DATEPICKERDIALOGID = 1

var selArrForDialog = new Array[ Boolean ](0)var degreeDropDownArr = new Array[ CharSequence ](0)

In der onCreate-Methode werden die zur Vorbereitung der Dialoge nötigen Da-ten geladen. Zum einen sind dies alle verfügbaren DegreeClasses14 aus dem gespei-cherten String „degreeJsonString“. Dieser wird in der Methode JsonProcessor.

14Die bei jedem News-Abruf aktualisiert werden.

Sebastian Stallenberger Seite 54 von 104

Page 59: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

jsonStringToDegreeList zu einer List[DegreeClassExt] und anschließend in derMethode SpiritHelpers.getDegreeMap zu einer Map geformt, die die Anzeigen-amen und dazugehörige Ids beinhaltet. Zum anderen werden aus der Preference„selectedCreationDegrees“ die letzten im Dialog selektierten DegreeClasses geladen.In mehreren Schritten werden die geladenen Daten in die Form transferiert, die derDialog zur korrekten Anzeige benötigt.

Listing 6.32: Laden der für den DegreeClass-Dialog benötigten Daten.val degreeJsonString = SpiritHelpers . loadString (

NewsCreate .this , " degreeJsonString ")val getAllDegreesObject =

JsonProcessor . jsonStringToDegreeList ( degreeJsonString ).asInstanceOf [List[ DegreeClassExt ]]

val degreeMap = SpiritHelpers . getDegreeMap ( this ,getAllDegreesObject , "")

degreeDropDownArr = SpiritHelpers . getDegreeTitleArr (degreeMap )

selArrForDialog = new Array[ Boolean ]( degreeDropDownArr .length)

val selectedDegreesString = SpiritHelpers . getStringPrefs (NewsCreate .this , " selectedCreationDegrees ", false)

if ( selectedDegreesString .equals("N/A")) {SpiritHelpers . setPrefs ( NewsCreate .this ,

" selectedCreationDegrees ", " AllClasses ", false)}

val selectedDegreesDiffArr = selectedDegreesString .split(" <;>")

for (i <- 0 until degreeDropDownArr .length) {val degreeClass = degreeDropDownArr (i)if ( selectedDegreesDiffArr . contains ( degreeClass )) {

selArrForDialog (i) = true} else {

selArrForDialog (i) = false}

}

Der Dialog benötigt dabei ein String-Array aller verfügbaren DegreeClasses unddazugehörig ein Boolean-Array, in dem festgehalten ist, welche Elemente selektiertsind. Die selektierten Elemente sind hierbei als ein String mit dem Trennzeichen„<;>“ zwischen den Elementen abgelegt. Nach allen Umformungen sind im ArraydegreeDropDownArr alle im Dialog anzuzeigenden Elemente vorhanden und im Ar-ray selArrForDialog die dazugehörigen Selektionen. Beide Arrays müssen gleichgroß sein.Weiterhin werden in der onCreate-Methode Events, wie z.B. onClick abgefangen.Bei Klick auf die DegreeClasses öffnet sich ein Dialog, über den die DegreeClassesausgewählt werden können. Bei Klick auf das ExpireDate öffnet sich dementspre-chend ein Dialog zur Auswahl des Datums.

Sebastian Stallenberger Seite 55 von 104

Page 60: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Listing 6.33: Setzen der onClick-Events für die GUI-Elemente. (Teil 1)val degreeTv = findViewById (R.id. degreeText ).

asInstanceOf [ TextView ]degreeTv . setOnClickListener (new OnClickListener {

def onClick (p1: View) {showDialog ( DEGREEDIALOGID )

}})

val expireDateTv = findViewById (R.id. datePexpiredegreeText ). asInstanceOf [ TextView ]

expireDateTv . setOnClickListener (new OnClickListener {def onClick (p1: View) {

showDialog ( DATEPICKERDIALOGID )}

})

Beim Klick auf den „Senden“-Button wird geprüft, ob der Betreff und die Nachrichtausgefüllt wurden. Ist eines von beiden leer, wird dies dem Nutzer über einen Toastsignalisiert. Sind beide Felder ausgefüllt, werden die zuvor gesammelten Daten Fh-sId, Betreff, Nachricht, Ablaufdatum und betroffene DegreeClasses dem NewsCrea-teTask übergeben, der diese als neue News einträgt.

Listing 6.34: Setzen der onClick-Events für die GUI-Elemente. (Teil 2)val sendButton = findViewById (R.id. createButton ).

asInstanceOf [Button][...]val message = findViewById (R.id. editMessage ).

asInstanceOf [ EditText ]. getText

sendButton . setText ( getString (R.string.string_send_as) +fhsId + ")")

sendButton . setOnClickListener (new OnClickListener {def onClick (p1: View) {

fhsId = SpiritHelpers . getStringPrefs (NewsCreate .this , " editFhsId ", false)

expireDate = SpiritHelpers . getStringPrefs ([...])degreeclass = SpiritHelpers . getStringPrefs ([...])

if ( subject . toString .equals("") ||message . toString .equals("")) {

Toast. makeText ( NewsCreate .this ,R.string.string_subjMess_must ,Toast.LENGTH_SHORT).show ()

} else {new NewsCreateTask ( NewsCreate .this). execute (

Array(fhsId , subject .toString ,message .toString , expireDate ,translateDegreeNameToId (degreeclass ,degreeMap )))

}}})updateDisplay ()

Sebastian Stallenberger Seite 56 von 104

Page 61: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Das Vorgehen in NewsCreateTask unterscheidet sich kaum von dem beim Anlegeneines neuen Kommentars, weshalb an dieser Stelle nicht weiter darauf eingegangenwird. Nach dem erfolgreichen Eintragen der News wird NewsCreate beendet und dieActivity NewsMulti aufgerufen.Da die REST-Schnittstelle als DegreeClasses jeweils die Ids entgegennimmt undnicht, wie in dieser Activity verwendet, die Namen, muss der String der selektiertenDegreeClasses vor dem Versand gewandelt werden. Dies geschieht in der MethodetranslateDegreeNameToId.

Listing 6.35: Die Methode translateDegreeNameToId.def translateDegreeNameToId ( degreeName: String ,

map: ListMap [String , Int ]): String = {val degreeNameArr = degreeName .split(" <;>")var returnString = ""for ( singleDegreeName <- degreeNameArr ) {

if ( singleDegreeName .equals( degreeNameArr .last)) {returnString = returnString + map. getOrElse (

singleDegreeName , ""). toString} else {

returnString = returnString + map. getOrElse (singleDegreeName , ""). toString + " <;>"

}}returnString

}

Der übergebene String wird anhand der Trennzeichen aufgesplittet. Anschließendwird in der Map, die in der onCreate-Methode erzeugt wurde, nach dem Namengesucht und für jedes einzelne Element die Id zurückgegeben. Aus den Ids wird wie-der ein String mit dem Trennzeichen „<;>“ zusammengebaut und von der Funktionzurückgegeben.In Listing 6.34 wird in der letzten Zeile die Methode updateDisplay aufgerufen.Diese sorgt dafür, dass die TextViews für die Anzeige der DegreeClasses und desExpireDates mit aktuellen Daten versehen werden. Dies ist zum Beispiel nach einerÄnderung der Daten über die Dialoge nötig.Wichtige Bestandteile dieser Activity sind die zwei Dialoge, die in diesem Kapi-tel bereits wiederholt erwähnt wurden. Aufgerufen werden diese über die Metho-den showDialog bei den weiter oben erwähnten onClick-Events. Verarbeitet wirdder Aufruf von showDialog in der in Listing 6.36 dargestellten Methode onCreateDialog.

Listing 6.36: Die Methode onCreateDialog.override def onCreateDialog (id: Int): Dialog = {

val c: Calendar = Calendar . getInstance ()val nowYear = c.get( Calendar .YEAR)val nowMonth = c.get( Calendar .MONTH)val nextMonth = nowMonth + 1val nowDay = c.get( Calendar .DAY_OF_MONTH)

Sebastian Stallenberger Seite 57 von 104

Page 62: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

id match {case DEGREEDIALOGID =>new AlertDialog . Builder (this). setTitle ( getString (

R.string.string_regardingDegrees )).

setMultiChoiceItems (degreeDropDownArr ,selArrForDialog ,new DialogInterface . OnMultiChoiceClickListener

{[...] }). setPositiveButton ( "OK",

new DialogInterface . OnClickListener {def onClick (dialog: DialogInterface ,

clicked: Int): Unit = {clicked match {

case DialogInterface .BUTTON_POSITIVE =>returnSelectedDegrees

}}}).create

case DATEPICKERDIALOGID =>new DatePickerDialog (this ,

mDateSetListener ,nowYear , nextMonth , nowDay)

}}

Darin wird je nach Dialog-Id entschieden, welcher Dialog angezeigt wird: Für denDegreeClass-Dialog wurde ein normaler AlertDialog15 mit Mehrfachauswahl gewählt.Nach dem Selektieren der gewünschten DegreeClasses wird durch Klick auf den Ok-Button die Methode returnSelectedDegrees aufgerufen, die die Auswahl in einenString umwandelt und in den Preferences abspeichert.

Listing 6.37: Die Methode returnSelectedDegrees.def returnSelectedDegrees : Unit = {

{var i: Int = 0var selectedDegreesString = ""

while (i < degreeDropDownArr .size) {if ( selArrForDialog (i)) {

selectedDegreesString = selectedDegreesString +degreeDropDownArr (i) + " <;>"

}i += 1

}if ( selectedDegreesString .equals("")) {

selectedDegreesString = getString (R.string.string_all) + " <;>"

}

15Vgl. http://developer.android.com/reference/android/app/AlertDialog.html

Sebastian Stallenberger Seite 58 von 104

Page 63: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

selectedDegreesString = selectedDegreesString .substring (0, selectedDegreesString .

length () - 3)SpiritHelpers . setPrefs ( NewsCreate .this ,

" selectedCreationDegrees ", selectedDegreesString ,false)

updateDisplay ()}

}

Der Dialog für das ExpireDate ist ein DatePickerDialog16, der nach der Datums-Auswahl ebenfalls das Datum wandelt und als Preference ablegt. Dies geschieht dies-mal allerdings über einen DatePickerDialog.OnDateSetListener namens mDateSetListener.

Listing 6.38: Der Listener mDateSetListener.val mDateSetListener : DatePickerDialog . OnDateSetListener =

new DatePickerDialog . OnDateSetListener () {def onDateSet (view: DatePicker , year: Int ,

monthOfYear : Int , dayOfMonth: Int) {val month = monthOfYear + 1SpiritHelpers . setPrefs ( NewsCreate .this ,

" createNewsExpireDate ", year. toString + "-" +fillStringWithNull (month. toString ) + "-" +

fillStringWithNull ( dayOfMonth . toString ) +" 00:00:01", false)

updateDisplay ()}

}

Damit sind die wichtigsten Elemente der Activity NewsCreate erläutert worden. Imfolgenden Kapitel stellt der Autor die Activity Settings vor, die die Auswahl derEigenschaften beinhaltet.

6.7 Activity SettingsDie Activity Settings unterscheidet sich von den anderen Activities darin gehend,dass sie eine PreferenceActivity17 ist. Eine PreferenceActivity erlaubt den struktu-rellen Aufbau eines Menüs, über das der Nutzer Einstellungen für die Applikationvornehmen kann. Die Elemente werden hierbei über eine XML-Datei gesetzt, diediesmal allerdings nicht im Ordner res/layouts, sondern im Ordner res/xml liegt.Das Besondere an der PreferenceActivity ist, dass sie automatisch für jedes in derXML-Datei angegebene Element eine Preference anlegt und wenn der Nutzer eineEinstellung ändert, diese auch sofort übernimmt.In Listing 6.39 ist der Aufbau dieser XML-Datei für die Settings von SpiritMobile zusehen. Umschlossen von einem PreferenceScreen-Tag sind die PreferenceCategory-

16Vgl. http://developer.android.com/reference/android/app/DatePickerDialog.html17Vgl. http://developer.android.com/reference/android/preference/PreferenceActivity.html

Sebastian Stallenberger Seite 59 von 104

Page 64: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Tags für das Anlegen von Kategorien zuständig. Diese bilden eine Art von Über-schriften für die anderen Elemente. In der Kategorie Login wurden zwei EditText-Preferences für die Eingabe der Nutzerdaten angelegt. Die folgende CheckBoxPre-ference soll dem Nutzer dann signalisieren, ob er eingeloggt ist, weshalb die Attri-bute android:enabled und android:clickable auch auf false stehen. Für dieNews und den Stundenplan sind in der prototypischen Implementierung noch kei-ne Elemente vorhanden. Im Abschnitt Debugging kann der Nutzer wählen, ob dieApplikation die Daten im Standalone-Modus oder vom Server beziehen soll.

Listing 6.39: Die XML-Datei für die Settings.<?xml version="1.0" encoding="utf -8"?>

<PreferenceScreen xmlns:android="http:// schemas .andro ..."android:layout_width="fill_parent"android:layout_height="fill_parent">

<PreferenceCategoryandroid:title="Login">

<EditTextPreferenceandroid:name="FhsId"android:summary="Gib hier deine FhsId an."android: defaultValue =""android:title="FhsId"android:key=" editFhsId " />

<EditTextPreferenceandroid:name=" Passwort "android:summary="Gib hier dein Passwort an."android: defaultValue =""android:title=" Passwort "android:key=" editPassword "android:password="true"/>

<CheckBoxPreferenceandroid:key=" loggedIn "android:title=" Eingeloggt ?"android:enabled="false"android: defaultValue ="false"android:clickable="false"/>

</ PreferenceCategory ><PreferenceCategory android:title="News">

</ PreferenceCategory ><PreferenceCategory android:title=" Stundenplan ">

</ PreferenceCategory ><PreferenceCategory android:title=" Debugging ">

<CheckBoxPreferenceandroid:title=" Standalone Mode"android: defaultValue ="true"android:summary="Zum Testen der Anwendung mit

fiktiven Daten."android:key=" standalone "/>

</ PreferenceCategory ></ PreferenceScreen >

Sebastian Stallenberger Seite 60 von 104

Page 65: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Wie der Nutzer diesen Aufbau sieht, kann man in Abbildung 6.3 in einem Screenshotsehen.

Abbildung 6.3: Screenshot der PreferenceActivity Settings

Die eigentliche PreferenceActivity ist in den folgenden Listings 6.40, 6.41 und 6.42dargestellt. Nachdem per addPreferencesFromResource die XML-Datei festgelegtwurde, werden in der onCreate-Methode die DefaultSharedPreferences und dieSharedPreferences des PreferenceScreen geladen. Die DefaultSharedPreferencessind nötig, da die Preference „role“ nicht über die Einstellungen änderbar ist undsomit auch keine Preference der SharedPreferences der PreferenceActivity Settingsist.

Listing 6.40: Die PreferenceActivity Settings. (Teil 1)class Settings extends PreferenceActivity with

OnSharedPreferenceChangeListener {override def onCreate ( savedInstanceState : Bundle) {

super. onCreate ( savedInstanceState )addPreferencesFromResource (R.xml. preferences );

val pref: SharedPreferences = PreferenceManager .getDefaultSharedPreferences (this)

val sp: SharedPreferences = getPreferenceScreen ().getSharedPreferences ()

val name = findPreference (" editFhsId ").asInstanceOf [ Preference ]

if (name. asInstanceOf [ EditTextPreference ]. getText .equals("")) {

name. setSummary ( getString (R.string.string_notSetYet ))

} else {name. setSummary (sp. getString (" editFhsId ", ""))

}

Sebastian Stallenberger Seite 61 von 104

Page 66: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

val password = findPreference (" editPassword ").asInstanceOf [ Preference ]

if ( password . asInstanceOf [ EditTextPreference ].getText .equals("")) {

password . setSummary ( getString (R.string.string_notSetYet ))

} else {password . setSummary (

sp. getString (" editPassword ", "").replaceAll (".", "*"))

}

val role = SpiritHelpers . getStringPrefs (Settings .this , "role", false)

val loggedIn = findPreference (" loggedIn ").asInstanceOf [ CheckBoxPreference ]

if (role.equals("")) {loggedIn . setSummary ( getString (

R.string.string_ notLoggedIn ))} else {

loggedIn . setSummary ( getString (R.string.string_loggedInAs ) + role. toString )

}}

Die Summary eines Elements kann als erläuternder Text definiert werden. Im Fallder EditTexts von name (FhsId) und password wird sie dazu genutzt, dem Nutzerzu signalisieren, ob schon eine FhsId und ein Passwort gesetzt ist. Im Falle desPassworts werden alle Zeichen für die Anzeige durch „*“ ersetzt. Abhängig davon,ob eine role vorhanden ist bzw. ob der Nutzer eingeloggt ist, wird dem Nutzer derLogin-Status und seine Rolle über eine CheckBox und ihre Summary angezeigt.In den folgenden Methoden onPause und onResume wird der onSharedPreferenceChangeListener ab- und angemeldet. Die Anmeldung ist nötig, damit die MethodeonSharedPreferenceChanged eingesetzt werden kann. Die Abmeldung dagegen, umnicht unnötig Ressourcen zu verbrauchen, wenn der Listener nicht benötigt wird.

Listing 6.41: Die PreferenceActivity Settings. (Teil 2)override def onPause () {

getPreferenceScreen (). getSharedPreferences ().unregisterOnSharedPreferenceChangeListener ( Settings .this)

finish ()super. onPause ()

}

override def onResume () {super. onResume ()getPreferenceScreen (). getSharedPreferences ().

registerOnSharedPreferenceChangeListener ( Settings .this)

}

Sebastian Stallenberger Seite 62 von 104

Page 67: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Da in der PreferenceActivity Settings die einzelnen Preferences teilweise nicht ein-fach nur abgespeichert werden sollen, wird jede Eingabe des Nutzers über die inListing 6.42 dargestellte Methode onSharedPreferenceChanged überwacht und in-dividuell darauf reagiert.So soll das Passwort nicht im Klartext abgespeichert werden. Wird das Passwortvom Nutzer geändert, wird es durch die Methode SpiritHelpers.encryptStringverschlüsselt und dann erst abgelegt. Hat der Nutzer sowohl eine FhsId als auch einPasswort eingegeben, werden diese dem Task VerifyLoginDataTask zur Verifizierungübergeben. In Listing 6.43 kann man sehen, dass der Task bisher nur auf eine festvorgegebene Menge von FhsIds prüft und die entsprechende Rolle zurückgibt. Diesliegt daran, dass der REST-Service zur Verifizierung von Nutzerdaten noch nichtexistiert. Dem Nutzer wird über Toasts angezeigt, ob die Verifizierung erfolgreichoder nicht erfolgreich war.

Listing 6.42: Die PreferenceActivity Settings. (Teil 3)override def onSharedPreferenceChanged ( sharedPreferences :

SharedPreferences , key: String) {val pref = findPreference (key). asInstanceOf [ Preference ]

if (pref. isInstanceOf [ EditTextPreference ]) {val etp = pref. asInstanceOf [ EditTextPreference ]if (pref.getKey ().equals(" editPassword ")) {

val encryptedPass = SpiritHelpers . encryptString (etp. getText )

etp. setText ( encryptedPass ) // Instant encryptionpref. setSummary (etp. getText (). replaceAll (".",

"*"));} else {

pref. setSummary (etp. getText ());}

if (pref.getKey ().equals(" editFhsId ") ||pref.getKey ().equals(" editPassword ")) {

val un = findPreference (" editFhsId ").asInstanceOf [ EditTextPreference ]. getText

val pwd = findPreference (" editPassword ").asInstanceOf [ EditTextPreference ]. getText

if (!un.equals("") && !pwd.equals("")) {val role = new VerifyLoginDataTask ( Settings .this).

execute (Array(un , SpiritHelpers .decryptString (pwd))).get ()

if (role.equals("")) {val loggedIn = findPreference (" loggedIn ").

asInstanceOf [ CheckBoxPreference ]loggedIn . setChecked (false)SpiritHelpers . setPrefs (this , "role", "", false)loggedIn . setSummary ( getString (R.string.

string_ notLoggedIn ))} else {

val loggedIn = findPreference (" loggedIn ").asInstanceOf [ CheckBoxPreference ]

Sebastian Stallenberger Seite 63 von 104

Page 68: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

loggedIn . setChecked (true)SpiritHelpers . setPrefs (this , "role",

role.toString , false)loggedIn . setSummary ( getString (

R.string.string_loggedInAs )+ role. toString )}

} else {val loggedIn = findPreference (" loggedIn ").

asInstanceOf [ CheckBoxPreference ]loggedIn . setChecked (false)SpiritHelpers . setPrefs (this , "role", "", false)loggedIn . setSummary ( getString (

R.string.string_ enterUnAndPass ))}}}}}

Nachdem nun dank der Rückgabe des Tasks die Rolle des Nutzers feststeht, wirddiese und der Login-Status dem Nutzer nun angezeigt.

Listing 6.43: Die doInBackground-Methode des Tasks VerifyLoginDataTask.override protected def doInBackground (param: Array[String

]): String = {val username = param (0)if ( username .equals("braun") || username .equals("otto")

|| username .equals("knolle")) {" professor "}else if ( username .equals(" stallen3 ")) {

" student "} else {""}}

Von der PreferenceActivity Settings kommt der Autor im folgenden Kapitel nun zurActivity Info, die für die Anzeige einer Hilfe zuständig ist. Sie basiert auf einemFrameLayout, welches nur ein einziges Element enthalten darf. In diesem Fall istdas eine WebView18.

6.8 Activity InfoDie Activity Info ist die im Vergleich einfachste Activity in SpiritMobile.

Listing 6.44: Der Inhalt der info.xml.<?xml version="1.0" encoding="utf -8"?>

<FrameLayout xmlns:android="http:// schemas . android .com/apk/res/ android "

android:layout_width="fill_parent"android:layout_height="fill_parent">

<WebView android:layout_width="fill_parent"android:layout_height="fill_parent"android:id="@+id/ infowebview ">

</ WebView ></ FrameLayout >

18Vgl. http://developer.android.com/reference/android/webkit/WebView.html

Sebastian Stallenberger Seite 64 von 104

Page 69: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

In der onCreate-Methode der Activity wird die WebView zugänglich gemacht undanschließend ihre Methode loadData aufgerufen. Als Parameter bekommt diese Me-thode drei Strings: Den anzuzeigenden Inhalt (data), den Datentyp (mimeType) unddas Encoding. Der Inhalt (HTML-Seite) soll allerdings in res/raw (bzw. res/raw-de) ausgelagert werden, da so die Mehrsprachigkeit sehr einfach umgesetzt werdenkann19.

Listing 6.45: Der Inhalt der onCreate-Methode der Activity Info.setContentView (R.layout.info)val webView = findViewById (R.id. infowebview ).

asInstanceOf [ WebView ]webView . loadData ( readTextFromResource (R.raw.info),

"text/html", "UTF -8")

Hat man die HTML-Seiten in die raw-Ordner ausgelagert, muss man sie einlesen,um den entsprechenden String für die WebView verwenden zu können. Dies erledigtdie Methode readTextFromResource. Sie nimmt die Id der Ressource entgegen, liestdiese aus und gibt den Inhalt als String zurück.

Listing 6.46: Die Methode readTextFromResource.def readTextFromResource ( resourceID: Int): String = {

val raw = getResources (). openRawResource ( resourceID )val stream = new ByteArrayOutputStream ()var i: Int = 0try {

i = raw.read ()while (i != -1) {

stream.write(i)i = raw.read ()

}raw.close ()

}catch {

case e: IOException => Log.e("ERROR", e. getMessage .toString )

}stream. toString ()

}

Das Anzeigen der Hilfe ist also nichts weiter als das Laden einer Website in einerWebView und ist daher einfach zu realisieren. Das in der Activity Info angewandteVerfahren wird auch von Anwendungen genutzt, mit denen einfache Android Ap-plikationen per HTML und JavaScript programmiert werden können. Im folgendenAbschnitt werden die Toilers vorgestellt.

19raw enthält dann die englischsprachige Datei und raw-de die deutschsprachige. Je nachdemwelche Sprache im System eingestellt ist, wird der entsprechende Ordner automatisch gewählt.

Sebastian Stallenberger Seite 65 von 104

Page 70: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

6.9 ToilersUm die Funktionalität möglichst von den Activities zu trennen, wurden die so-genannten Toilers (deutsch: Arbeiter) eingeführt. Die wichtigsten Toilers sind hier-bei: JsonProcessor, SpiritConnect, SpiritHttpClient, ViewBuilder und SpiritHelpers.Diese sollen in diesem Kapitel erläutert und ihre wichtigsten Methoden dargestelltwerden.

6.9.1 JsonProcessor

Das Object JsonProcessor enthält sowohl alle Case-Classes für die Objekte, in denendie empfangenen Daten gelagert werden, als auch die Methoden, die zur Umwand-lung der JSON-Strings in diese Objekte benötigt werden. In Listing 6.47 sind diegerade angesprochenen Case-Classes zu sehen. Laut [OSV08, 263-265] sind Case-Classes in Scala eine sehr einfache Möglichkeit, Pattern-Matching auf Objekte an-zuwenden. Das Schlüsselwort case führt dazu, dass der Compiler folgende drei Ak-tionen für die Klasse durchführt:

• Er fügt eine Factory-Methode mit dem Namen der Klasse hinzu. Für die Klasseentfällt also das Schlüsselwort new.

• Er stellt vor die Argumente der Parameter-Liste jeweils das Schlüsselwort val,welches die Parameter zu Feldern macht.

• Er fügt die Methoden toString, hashCode und equals hinzu, welche immerfür den ganzen Objekt-Baum gelten.

[OSV08, 263-265]

Listing 6.47: Die Case Classes im Objekt JSON-Processor.case class NewsList (news: java.util.List[News ])

case class News( news_id: Int ,title: String ,content: String ,owner: Owner ,expireDate: String ,creationDate : String ,lastModified : String ,degreeClass : java.util.List[ DegreeClassExt ],newsComment : java.util.List[ NewsComment ])

case class Owner(fhs_id: String ,displayedName : String ,memberType: String)

case class NewsComment (comment_id: Int ,content: String ,creationDate : String ,owner: Owner)

Sebastian Stallenberger Seite 66 von 104

Page 71: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

case class DegreeClassExt (class_id: Int ,parent: Parent ,title: String ,classType: String ,mail: String ,subClasses: java.util.List[ DegreeClassExt ])

case class DegreeClassList (degreeClass : java.util.List[ DegreeClassExt ])

case class Parent(class_id: Int ,title: String)

Die einzelnen Methoden, in denen die JSON-Strings geparsed werden sind: jsonStringToNewsList, jsonStringToDegreeList und jsonStringToSingleNews. An-hand von jsonStringToSingleNews wird in Listing 6.48 gezeigt, wie der Vorgangdes Parsens abläuft.

Listing 6.48: Die Methode jsonStringToSingleNews.def jsonStringToSingleNews ( jsonString: String) = {

var workJsonString = jsonString

val gson = new Gson (). asInstanceOf [Gson]var gsonObject = gson. fromJson ( workJsonString ,

classOf [ NewsList ])

var newsJavaList = gsonObject .news. asInstanceOf [java.util.List[News ]]

var newsScalaList = newsJavaList .toList

newsScalaList}

Als Parser wird derzeit der Java-Parser GSON von Google genutzt. Nach demErzeugen einer Instanz von GSON wird dieser der JSON-String und die Klassen-Beschreibung von NewsList übergeben. Man erhält von GSON eine Java-Liste zu-rück. Diese wird anschließend in eine Scala-Liste umgewandelt und zurückgegeben.GSON ist ab API-Level 11 (Android 3.0.x) im Android-Framework als „JsonRea-der“20 enthalten.Neben GSON gibt es noch einige andere JSON-Parser, die sich für diese Aufgabeeignen würden. Programmiert man nativ in Scala, wäre die erste Wahl „lift-json“aus dem Lift-Framework. Leider funktionierte diese Bibliothek nicht in Kombinati-on mit Android. Eine Alternative wäre die Scala Bibliothek Jerkson21, welche aufdem JSON-Prozessor Jackson 22 basiert. Diese konnte auch nach Email-Kontakt mitdem Autor Coda Hale zum Implementations-Zeitpunkt nicht zum Laufen gebracht20Vgl. http://developer.android.com/reference/android/util/JsonReader.html21Vgl. https://github.com/codahale/jerkson22Vgl. http://jackson.codehaus.org/

Sebastian Stallenberger Seite 67 von 104

Page 72: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

werden. Laut [Sha09, 36m53s] kann durch den Einsatz von Stream-Parsern stattTree-Parsern unter Android Akku-Kapazität gespart werden. Jackson ist wie GSONein Stream-Parser und Jerkson wäre somit eine ideale Wahl für Scala.

6.9.2 SpiritHttpClient

Da der Server von Spirit HTTPS mit einem nicht verifizierten Zertifikat verwendet,muss statt des nativen HttpClient eine modifizierte Version mit eigenem Keystoreverwendet werden. Ohne diese ist die Verbindung nicht möglich.

Listing 6.49: Die Klasse SpiritHttpClient.class SpiritHttpClient (var context: Context ) extends

DefaultHttpClient {

override protected def createClientConnectionManager ():ClientConnectionManager = {

val registry = new SchemeRegistry ()registry . register (new Scheme("http",

PlainSocketFactory . getSocketFactory , 80))registry . register (new Scheme("https",

newSslSocketFactory (), 443))new SingleClientConnManager (getParams , registry )

}

private def newSslSocketFactory (): SocketFactory = {try {

var trusted = KeyStore . getInstance ("BKS")val in: InputStream = context . getResources .

openRawResource (R.raw. mykeystore )try {

trusted .load(in , " mysecret ". toCharArray )} finally {

in.close ();}val sf = new SSLSocketFactory ( trusted )sf. setHostnameVerifier ( SSLSocketFactory .

STRICT_HOSTNAME_VERIFIER )

sf} catch {

case e: Exception => throw new AssertionError (e);}

}}

Die Klasse SpiritHttpClient basiert auf dem DefaultHttpClient. In der überschrie-benen Methode createClientConnectionManager wird festgelegt, dass Verbindun-gen, die über den Post 443 stattfinden, über die SocketFactory aus newSslSocketFactory stattfinden sollen. In der Methode newSslSocketFactory wird der Typ desKeyStore definiert und anschließend über getResources.openRawResource der imOrdner res/raw liegende KeyStore mykeystore als InputStream eingelesen. Nach-

Sebastian Stallenberger Seite 68 von 104

Page 73: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

dem auch das Passwort „mysecret“ übergeben wurde, wird die konfigurierte Socket-Factory mit dem eigenen Keystore übergeben. Das Zertifikat wurde vorher von Handvom Server geladen und in den KeyStore abgelegt. Mit dem SpiritHttpClient bestehtnun die Möglichkeit, Verbindungen zum Spirit-Server aufzubauen.

6.9.3 SpiritConnect

Das Object SpiritConnect enthält die Methoden, die für den Verbindungsaufbaubzw. die Beschaffung der JSON-Strings nötig sind. Die Basis-Methoden sind hierbeigetJsonFromUrl und putJsonToUrl.In der Methode getJsonFromUrl wird zu Beginn kontrolliert, ob der Standalone-Modus aktiviert ist, indem die Preference „standalone“ ausgelesen wird. Ist dies derFall, wird die Aufgabe, den JSON-String zu beschaffen, an die Methode StandaloneOps.getJsonFromUrl weitergegeben. Diese gibt zu Testzwecken einen einfachen,fixen JSON-String zurück. Ist der Standalone-Modus deaktiviert, wird die Verbin-dung über den SpiritHttpClient aufgebaut. Über die setHeader-Methode von Http-Get wird dem Server mitgeteilt, ob man den String im JSON- oder XML-Formatempfangen möchte. Nach dem Verbindungsaufbau wird die Antwort des Servers alsString zurückgegeben.

Listing 6.50: Die Methode getJsonFromUrl.def getJsonFromUrl ( context: Context , restUrl: String):

String = {var returnString = ""if ( SpiritHelpers . getBoolPrefs ( context .

asInstanceOf [ Activity ], " standalone ")) {try {

returnString = StandaloneOps . getJsonFromUrl (context , restUrl )

} catch {case e: Exception =>

Log.e(" EXCEPTION ", e. getMessage )}

} else {val basicHttpContext = new BasicHttpContextval spiritHttpClient = new SpiritHttpClient ( context )val httpGet = new HttpGet ( restUrl )httpGet . setHeader ("Accept", " application /json")try {

val response = spiritHttpClient . execute (httpGet ,basicHttpContext )

val inputStream = response . getEntity . getContentreturnString = SpiritHelpers . convertStreamToString (

inputStream )} catch {

case e: Exception =>Log.e(" EXCEPTION ", e. getMessage )

}}returnString

}

Sebastian Stallenberger Seite 69 von 104

Page 74: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

In Listing 6.51 ist die Methode putJsonToUrl zu sehen. Ähnlich, wie in Listing 6.50in der Methode getJsonFromUrl, wird auch hier eine Verbindung zum Spirit-Serveraufgebaut. Allerdings kommt diesmal ein HttpPut-Objekt zum Einsatz. Zurück gibtdiese Methode ebenfalls die Antwort des Servers.

Listing 6.51: Die Methode putJsonToUrl.def putJsonToUrl ( context: Context , restUrl: String ,

putJson: String): String = {var returnString = ""val basicHttpContext = new BasicHttpContext ()

val spiritHttpClient = new SpiritHttpClient ( context )spiritHttpClient . getParams . setParameter (

CoreProtocolPNames .HTTP_CONTENT_CHARSET , HTTP.UTF_8)val httpPut = new HttpPut ( restUrl )val stringEntity = new StringEntity ( putJson )

httpPut . setEntity ( stringEntity )httpPut . setHeader ("Accept", " application /json")httpPut . setHeader ("Content -Type", " application /json")

try {val response = spiritHttpClient . execute (httpPut ,

basicHttpContext )returnString = EntityUtils . toString (

response . getEntity )} catch {

case e: Exception =>Log.e(" EXCEPTION ", e. getMessage )

}returnString

}

Um in SpiritMobile zu überprüfen, ob eine Internet-Verbindung besteht, wurde dieMethode checkInternetConnection genutzt, die in Listing 6.52 zu sehen ist.

Listing 6.52: Die Methode checkInternetConnection.def checkInternetConnection ( context: Context ):Boolean = {

val connectivityManager = context . getSystemService (Context . CONNECTIVITY _SERVICE ).

asInstanceOf [ ConnectivityManager ]if ( connectivityManager . getActiveNetworkInfo != null

&& connectivityManager . getActiveNetworkInfo .isAvailable

&& connectivityManager . getActiveNetworkInfo .isConnected )

{true

} else {false

}}

Sebastian Stallenberger Seite 70 von 104

Page 75: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Stellvertretend für alle Methoden, die über die Basis-Methoden agieren, wird nungetNews besprochen. Zu Beginn wird die URL23 zusammengesetzt und die Anfragean den Server gestellt. Das Ergebnis wird anschließend auf Strings geprüft, die aufeinen Fehler in der Abfrage hinweisen.

Listing 6.53: Die Methode getNews.def getNews ( context: Context ): Boolean = {

var returnBoolean = falseval newsUrl = "https://" + context . getString (

R.string. ipadress ) + ":" +context . getString (R.string.port) +

"/fhs -spirit/news"

val newsJsonString = SpiritConnect . getJsonFromUrl (context , newsUrl ). asInstanceOf [String]

if ( newsJsonString =="" || newsJsonString =="Bad URI4" ||newsJsonString == "Bad") {

returnBoolean = false} else {

SpiritHelpers . saveString (context , " newsJsonString ",newsJsonString )

SpiritHelpers . setLastNewsDate ( context .asInstanceOf [ Activity ])

returnBoolean = true}returnBoolean

}

War die Abfrage erfolgreich, wird der String als „newsJsonString“ abgespeichert, dasaktuelle Datum als Datum des letzten Updates gesetzt und true zurückgegeben.War die Abfrage nicht erfolgreich, wird false zurückgegeben.Die Methode createNews ist der gerade vorgestellten sehr ähnlich und wird daherhier nicht gelistet. Der Basis-Methode wird hier allerdings ein vorher zusammenge-setzter JSON-String übergeben, welchen diese an den Server schickt. Anschließendwird wieder auf Erfolg geprüft. Es gibt für jede Kommunikation mit dem Server eineeigene Methode.

6.9.4 ViewBuilder

Das Object ViewBuilder beinhaltet die Methoden, die für den Aufbau der diversenViews in SpiritMobile zuständig sind. Diese sind sich alle sehr ähnlich. Teilweisewurde auf diese in den vorhergehenden Kapiteln schon eingegangen, weshalb eineerneute Behandlung an dieser Stelle vermieden werden soll.

23Uniform Resource Locator

Sebastian Stallenberger Seite 71 von 104

Page 76: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

6.9.5 SpiritHelpers

Im Objekt SpiritHelpers sind Methoden ausgelagert, die an mehreren Stellen imProgramm genutzt werden, aber nicht zu einer Kategorie zusammengefasst werdenkönnen. Die wichtigsten dieser Methoden werden in diesem Abschnitt erläutert.Zum Einzeiler convertStreamToString gibt es nicht viel zu sagen. Die Methodevereinfacht die Umwandlung eines InputStream zu einem String.

Listing 6.54: Die Methode convertStreamToString.def convertStreamToString (is: InputStream ): String = {

scala.io.Source. fromInputStream (is). getLines . mkString}

In Listing 6.55 sind die Methoden loadString und saveString zu sehen. Überdiese können einfach Strings in Textdateien gespeichert und aus Textdateien geladenwerden.

Listing 6.55: Die Methoden loadString und saveString.def loadString ( context: Activity , filename: String):

String = {var string = ""try {

string = convertStreamToString ( context .openFileInput ( filename ))

} catch {case e: Exception => Log.e(" EXCEPTION ",

e. getMessage . toString )}string

}

def saveString ( context: Context , filename: String ,string: String) {

var fos: FileOutputStream = nulltry {

fos = context . openFileOutput (filename ,Context .MODE_PRIVATE )

fos.write(string. getBytes )} catch {

case e: Exception =>Log.e(" EXCEPTION ", e. getMessage )

} finally {if (fos != null) {

fos.close ()}

}}

Durch die Übergabe von MODE_PRIVATE wird gewährleistet, dass von anderen Ap-plikationen auf die Strings nicht zugegriffen werden kann.Eine ähnliche Funktion haben die Funktionen setStringPrefs, getStringPrefsund getBoolPrefs. Allerdings erleichtern diese nicht den Zugriff auf Textdateien im

Sebastian Stallenberger Seite 72 von 104

Page 77: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Datei-System sondern auf die SharedPreferences von Android. Die beiden Methodenfür das Schreiben und Lesen von Strings sind in Listing 6.56 zu sehen.

Listing 6.56: Die Methoden setStringPrefs und getStringPrefs.def setStringPrefs ( activity: Activity , key: String ,

paravalue: String , encrypt: Boolean ) {val pref: SharedPreferences = PreferenceManager .

getDefaultSharedPreferences ( activity )val edit: Editor = pref.edit ()var value = paravalueif ( encrypt ) {

value = encryptString (value)}edit. putString (key , value)edit.commit ()

}

def getStringPrefs ( activity: Activity , key: String ,decrypt: Boolean ): String = {

val context = activity . asInstanceOf [ Context ]PreferenceManager . setDefaultValues (context ,

R.xml.preferences , false)val pref: SharedPreferences = PreferenceManager .

getDefaultSharedPreferences ( activity )

var value = pref. getString (key , "N/A")if ( decrypt ) {

value = decryptString (value)}value

}

Sie beschaffen sich eine Referenz auf den PreferenceManager bzw. die DefaultSha-redPreferences. Über den Booleschen Parameter encrypt bzw. decrypt kann dieVerschlüsselung bzw. Entschlüsselung aktiviert werden. Diese wird dann von denMethoden encryptString bzw. decryptString ausgeführt. Derzeit sind diese Me-thoden allerdings noch leer, da die Verschlüsselungs-Algorithmen zu BufferOverflow-Exceptions führten.Über die Methode getBoolPrefs bekommt man Boolesche Werte aus den Prefe-rences, wie z.B. ob der Standalone-Modus aktiv oder nicht aktiv ist.

Listing 6.57: Die Methode getBoolPrefs.def getBoolPrefs ( activity: Activity , key: String):

Boolean = {val context = activity . asInstanceOf [ Context ]PreferenceManager . setDefaultValues (context ,

R.xml.preferences , false)val pref: SharedPreferences = PreferenceManager .

getDefaultSharedPreferences ( activity )pref. getBoolean (key , true)

}

Sebastian Stallenberger Seite 73 von 104

Page 78: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Sie bedient sich hierbei der gleichen Prinzipien wie die vorhergehenden Funktionen,greift allerdings mit getBoolean statt mit getString auf die Werte zu.In Listing 6.58 ist die Methode zu sehen, die für das Setzen des aktuellen Datumsals Datum des letzten Updates verantwortlich ist.

Listing 6.58: Die Methode setLastNewsDate.def setLastNewsDate ( context: Context ) {

val df: SimpleDateFormat = new SimpleDateFormat ("dd.MM.yyyy HH:mm:ss")

SpiritHelpers . setStringPrefs ( context .asInstanceOf [ Activity ], " LastNewsDate ", df.format(

new Date ()). toString + context . getString (R.string.string_oclock), false)

}

In Abschnitt 6.6 wurde auf die Methode getDegreeMap verwiesen, die eine Liste vonDegreeClassExt-Objekten in eine ListMap[String, Int] umwandelt. In Listing 6.59ist diese zu sehen.

Listing 6.59: Die Methode getDegreeMap.def getDegreeMap ( context: Context ,

list: List[ DegreeClassExt ], prefix: String):ListMap [String , Int] = {

var degreeMap = new ListMap [String , Int]list. foreach (

element => {val degreeClassExt = element . asInstanceOf

[ DegreeClassExt ]var title = degreeClassExt .titleif ( degreeClassExt .title.equals(" AllClasses ")) {

title = context . getString (R.string.string_all)}

if ( degreeClassExt . classType .equals("Group")) {title = prefix + " - " + context . getString (

R.string.string_group) + " " + title}

degreeMap += title -> degreeClassExt .class_idif ( degreeClassExt . subClasses != null) {

degreeMap = degreeMap ++ getDegreeMap (context ,degreeClassExt . subClasses .toList , title)

}}

)degreeMap = ListMap ( degreeMap .toList.sortBy {

_._1}: _*)degreeMap

}

Sebastian Stallenberger Seite 74 von 104

Page 79: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

6. Prototypische Implementierung Fachhochschule Schmalkalden SS 2011

Dazu werden für alle Elemente des Parameters list der Name ausgelesen und ge-prüft, ob ein Parent-Objekt vorhanden ist und ob es sich um eine Gruppe handelt.Hat es ein Parent-Objekt, wird der Name mit dem Präfix „NameDesParentObjects- „ erweitert. Ist das Element eine Gruppe, bekommt es als direkten Präfix „ Grup-pe “. Anschließend wird der Name zusammen mit der Id als Tupel in der ListMapabgelegt. Bevor die ListMap zurückgegeben wird, wird sie noch nach Name sortiert.Im aktuellen Kapitel wurden die wichtigsten Elemente aus der prototypischen Im-plementierung von SpiritMobile gezeigt. Im folgenden Kapitel 7 wird nun gezeigt,welche Voraussetzungen eine Applikation für eine Veröffentlichung erfüllen muss undwie dies im Android Market vor sich geht.

Sebastian Stallenberger Seite 75 von 104

Page 80: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

7 DistributionNeben dem offiziellen Android Market1 gibt es noch andere Möglichkeiten, die Ap-plikation an den Nutzer zu bringen. So stellen alternative Markets2 wie z.B. Andro-idPIT App Center3 oder SlideME4 eine Möglichkeit dar, die bei kostenpflichtigenApps sogar einen Vorteil bringen kann. Will man im offiziellen Market eine kosten-pflichtige App erwerben, ist für die Bezahlmethode Google Checkout aktuell eineKreditkarte unabdingbar. Alternative Markets bieten neben Kreditkarte oft andereZahlungsoptionen wie Paypal oder ClickandBuy an.Im Rahmen dieser Masterarbeit soll betrachtet werden, wie eine Applikation in demAndroid Market bereitgestellt werden kann. Um eine App im offiziellen AndroidMarket anzubieten, bestehen gewisse Voraussetzungen. Soweit nicht anders angege-ben gilt für dieses Kapitel [Goo11h] als Quelle.

1. Der Entwickler muss über seinen Google Account einen Publisher Accounterstellen 5. Dieser kostet einmalig 25$ und hat keine weiteren Folgekosten.

2. Die App muss mit einem gültigen Schlüssel signiert sein. Das Ablaufdatumdes Schlüssels muss nach dem 22. Oktober 2033 liegen.

3. Es müssen folgende Attribute im <manifest>-Tag des Android Manifest defi-niert sein: android:versionCode und android:versionName.

4. Im <application>-Tag müssen android:icon und android:label definiertsein.

Zusätzlich zu den gerade genannten Voraussetzungen gibt es auf Android Devel-opers6 eine ausführliche Checkliste zur Vorbereitung einer Veröffentlichung.SpiritMobile7 steht derzeit als Closed Beta zum Download über den Market bereit.Der Weg dorthin soll nun kurz beschrieben werden.Wichtig ist es, das Attribut debug im Android Manifest auf false zu setzen. Das dar-auf hin über SBT erzeugte *.apk-Paket ist unsigniert. Es befindet sich bei Nutzungvon SBT mit android-plugin in <ProjektVerzeichnis>\target\scala_2.x.x. Über dieKonsole kann man mit dem einfachen Befehl sbt prepare-market das Paket signie-ren. Das android-plugin geht dabei davon aus, dass der Keystore mit den Signatur-Daten im Nutzerverzeichnis des Betriebssystems liegt und „.keystore“ heisst. DerPfad muss unter Umständen angepasst werden. Danach muss zipalign darauf an-gewendet werden. Sollte dies fehlschlagen, können alle Schritte allerdings auch ma-

1https://market.android.com2Eine ausführliche Auflistung gibt es unter http://de.wikipedia.org/wiki/Android_Market3http://www.androidpit.de/de/android/market/appcenter4http://slideme.org/5Vgl. https://market.android.com/publish6Vgl. http://developer.android.com/guide/publishing/preparing.html7https://market.android.com/details?id=de.fhs.spirit

Sebastian Stallenberger Seite 76 von 104

Page 81: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

7. Distribution Fachhochschule Schmalkalden SS 2011

nuell durchgeführt werden. Eine Anleitung dafür steht im Kapitel A.1.6 im Anhangzur Verfügung. [Ber11]Das aus diesen Schritten resultierende Paket ist nun bereit für den Upload in denMarket. Nachdem man sich als Developer im Market8 eingeloggt hat, sieht man eineÜbersicht der bestehenden Projekte, falls vorhanden. Hier kann man sein geradesigniertes Paket hochladen und nach erfolgreicher Überprüfung mehr Informationenzur Applikation bereitstellen. Zu diesen Informationen gehören unter anderem:

• Inhalte– Screenshots: Zwei Screenshots im PNG- oder JPG-Format sind Pflicht.– Symbol (Icon): Ein Icon der Größe 512*512px.– Werbegrafik, Funktionsgrafik, Werbevideo: Optionale zusätzliche Grafi-

ken und Videos.• Details

– Sprache: Hier können mehrere Sprachen angegeben und eine Sprache alsDefault-Sprache ausgewählt werden. Die folgenden mit „x“ gekennzeich-neten Punkte müssen jeweils für jede Sprache ausgefüllt werden.

– Titel (x): Der Titel der Applikation.– Description (x): Die Beschreibung der Applikation.– Recent Changes (x): Änderungen seit der letzten Version.– Promo Text (x)– App-Typ: Auswahl zwischen Apps/Spiele.– Kategorie: Die Kategorie, in der die Applikation gelistet werden soll.

• Veröffentlichungsoptionen– Inhaltsbewertung: Einteilung der Applikation in eine Jugendschutz-Stufe.– Preis: Der Preis für die Applikation.– Länder: Länder, in denen die Applikation verfügbar sein soll.– App-Typ: Auswahl zwischen Apps/Spiele.– Kategorie: Die Kategorie, in der die Applikation gelistet werden soll.

Nachdem man diese Informationen angegeben hat, kann die App im Market ver-öffentlicht werden. Obwohl Google kein Review der Apps durchführt, kann diesdurchaus eine Weile9 dauern. Wenn man seine App updaten will, lädt man das neue*.apk hoch, deaktiviert das alte *.apk und aktiviert das neue. Die Verteilung an dieGeräte wird dann automatisch durchgeführt. Der Nutzer erhält eine Meldung, dasseine neue Version der App verfügbar sei und kann diese updaten. Seit neuestem istes auch möglich, für eine App mehrere *.apk-Pakete einzustellen. Dies kann sinnvollsein, wenn sich zum Beispiel die App-Version für Smartphones von der für Tabletsstark unterscheidet.Im folgenden Kapitel wird ein Fazit gezogen und ein Ausblick auf die möglicheZukunft von SpiritMobile gegeben.

8Vgl. https://market.android.com/publish9Im Fall von SpiritMobile ca. 30 - 90 Minuten.

Sebastian Stallenberger Seite 77 von 104

Page 82: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

8 FazitDiese Arbeit hat gezeigt, dass es derzeit möglich ist, eine Android-Anwendung fast1

komplett in Scala zu schreiben. Allerdings fühlt sich die Entwicklung mit Java undEclipse deutlich ausgereifter und produktiver an. Das liegt zum einen daran, dassdas Android-SDK in Java geschrieben und für Java optimiert wurde. Zum anderenist Scala in Verbindung mit Android bisher ungenügend in aktuelle Entwicklungsum-gebungen integriert. Hier hat sich in den letzten Monaten allerdings einiges getan.Laut Meinung des Autors wird es auch zukünftig deutliche Fortschritte geben, da- verfolgt man Nutzer-Anfragen in Foren und Blog-Einträge - die Entwicklung vonAndroid-Anwendungen mit Scala immer mehr Interessenten hat.Entwickelt man mit Java eine Android-Applikation, so nutzt diese die Java-Libraries,die in Android vorhanden sind. Nutzt man Scala, wird auf die Scala-Libraries zu-rückgegriffen, die nicht in Android vorhanden sind. Dies hat zur Folge, dass in Scalageschriebene Anwendungen mehr Speicherplatz benötigen, da die Scala-Librariesmit in das *.apk-Paket gepackt werden müssen. Der Einsatz von Proguard mini-miert dieses Problem allerdings dahingehend, dass nur die Scala-Libraries gepacktwerden, die auch benötigt werden. Der Unterschied im Speicherverbrauch wird somitvernachlässigbar klein.Offizielle Studien, die Java und Scala hinsichtlich der Performance vergleichen, liegendem Autor nicht vor. Veröffentlicht wurde 2009 lediglich ein Testlauf von [Das09].Dort schnitt Scala noch deutlich schlechter ab als Java. Es liegen leider keine Er-gebnisse vor, die mit aktuellen Scala-Versionen erzielt wurden.Die Entwicklung in Scala macht nach Meinung des Autors wirklich Spaß und Ja-va erscheint einem in vielen Situationen plötzlich sehr umständlich. Leider trübenimmer wieder auftretende Integrations-Probleme den Workflow und daher ist leiderderzeit von einem produktiven Einsatz noch abzuraten.Ideen für die zukünftige Entwicklung von SpiritMobile gibt es viele. So wäre dieEntwicklung eines Authentifizierung-Moduls in der REST-Schnittstelle und die dazupassende Implementierung einer Nutzerdaten-Verifizierung in der Applikation einwichtiger Punkt, der für einen produktiven Einsatz der Applikation unabdingbarist. Auch ein regelmäßiger Abruf der News im Hintergrund über einen Service wäremöglich und wünschenswert. Sollten neue Informationen vorliegen, könnte das demNutzer über eine Status-Bar-Notification2 signalisiert werden. Des Weiteren könnteder Einsatz eines Widgets3 in Betracht gezogen werden. So hätte der Nutzer direktauf einem seiner Screens die letzten News im Blickfeld, ohne extra die Applikationstarten zu müssen.

1bis auf wenige Details, wie z.B. das Problem mit dem AsyncTask2Vgl. http://developer.android.com/guide/topics/ui/notifiers/notifications.html3Vgl. http://developer.android.com/reference/android/widget/package-summary.html

Sebastian Stallenberger Seite 78 von 104

Page 83: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

8. Fazit Fachhochschule Schmalkalden SS 2011

Denkt man noch einen Schritt weiter, könnte das Smartphone mit mobiler Applika-tion irgendwann den Studentenausweis ersetzen oder zumindest sinnvoll ergänzen.So könnte in Mensen damit gezahlt werden oder Studenten könnten bei Prüfun-gen leichter erfasst und authentifiziert werden. Für neue Studenten könnten virtu-elle Campus-Führungen stattfinden oder es könnte per Augmented Reality gezeigtwerden, wie der Campus früher einmal aussah. Auch Informationen zu einzelnenGebäuden, wie zum Beispiel sich häufig wechselnde Öffnungszeiten, könnten demStudenten nach Abruf eines QR-Codes angezeigt werden.Alles in allem steckt noch sehr viel Potential in SpiritMobile, unabhängig davon, wel-ches Betriebssystem man betrachtet. Mobile Applikationen werden einmal Grund-voraussetzung für die einfache Kommunikation zwischen Studenten und Hochschulensein. Sie erleichtern sowohl den Studenten das Studieren als auch den Hochschulendie Verwaltung.

Sebastian Stallenberger Seite 79 von 104

Page 84: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Literaturverzeichnis[ass11] assembla.com: scala-android-ant-snippet.txt. https://www.assembla.

com/spaces/scala-ide/documents/ajkjugweOr34DAeJe5cbCb/download/scala-android-ant-snippet.txt, Juli 2011. – abgeru-fen am: 15.09.2011

[Ber11] Berkel, Jan: android-plugin Readme. https://github.com/jberkel/android-plugin/blob/master/README.markdown, Juli 2011. – abgeru-fen am: 17.08.2011

[BP10] Becker, Arno ; Pant, Marcus: Android 2, 2. Auflage. dpunkt.verlagGmbH, 2010. – Heidelberg

[Bra11] Braun, Oliver: SCALA – Objektfunktionale Programmierung, 1. Auflage.Carl Hanser Verlag, 2011. – www.hanser.de

[Bre11] Brechtel, James: Building Android Apps with Sca-la - IntelliJ. http://nevercertain.com/blog/2011/02/18/scala-android-intellij-win-part-3/, Februar 2011. – abgeru-fen am: 15.08.2011

[Dar10] Darcey, Lauren: Working with NinePatch Stretchable Graphics in An-droid. http://www.developer.com/ws/other/article.php/3889086/Working-with-NinePatch-Stretchable-Graphics-in-Android.htm,Juni 2010. – abgerufen am: 11.08.2011

[Das09] Dashrath, Akshay: Results: Scala Vs Java. http://www.akshaydashrath.com/2009/11/results-scala-vs-java.html, Novem-ber 2009. – abgerufen am: 13.09.2011

[Goo11a] Google: Activity. http://developer.android.com/reference/android/app/Activity.html, August 2011. – abgerufen am: 28.08.2011

[Goo11b] Google: Android Debug Bridge. http://developer.android.com/guide/developing/tools/adb.html, August 2011. – abgerufen am:11.08.2011

[Goo11c] Google: Application Fundamentals. http://developer.android.com/guide/topics/fundamentals.html, August 2011. – abgerufen am:07.09.2011

[Goo11d] Google: AsyncTask. http://developer.android.com/reference/android/os/AsyncTask.html, August 2011. – abgerufen am: 28.08.2011

Sebastian Stallenberger80

Page 85: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Literaturverzeichnis Fachhochschule Schmalkalden SS 2011

[Goo11e] Google: Installing the SDK. http://developer.android.com/sdk/installing.html, Juni 2011. – abgerufen am: 10.08.2011

[Goo11f] Google: Intent. http://developer.android.com/reference/android/content/Intent.html, August 2011. – abgerufen am:31.08.2011

[Goo11g] Google: Platform Versions. http://developer.android.com/resources/dashboard/platform-versions.html, August 2011. – ab-gerufen am: 08.08.2011

[Goo11h] Google: Publishing on Android Market. http://developer.android.com/guide/publishing/publishing.html, August 2011. – abgerufenam: 17.08.2011

[Goo11i] Google: SDK Tools. http://developer.android.com/guide/developing/tools/index.html#tools-sdk, August 2011. – abgerufenam: 11.08.2011

[Goo11j] Google: What is Android? http://developer.android.com/guide/basics/what-is-android.html, August 2011. – abgerufen am:09.08.2011

[Guy09] Guy, Romain: Drawable mutations. http://www.curious-creature.org/2009/05/02/drawable-mutations/, Mai 2009. – abgerufen am:29.08.2011

[IDC11] IDC: Press Release. http://www.idc.com/getdoc.jsp?containerId=prUS22871611, Juni 2011. – abgerufen am: 09.08.2011

[jso11] json.org: Introducing JSON. http://www.json.org/, August 2011. –abgerufen am: 24.08.2011

[lan08] lang.org scala: A Tour of Scala. http://www.scala-lang.org/node/104, Juli 2008. – abgerufen am: 13.08.2011

[OSV08] Odersky, Martin ; Spoon, Lex ; Venners, Bill: Programming in Scala.Artima Press, 2008

[Sø11a] Sørensen, Carsten E.: CreateNewScalaProject. https://code.google.com/p/treeshaker/wiki/CreateNewScalaProject, August 2011. – ab-gerufen am: 15.08.2011

[Sø11b] Sørensen, Carsten E.: SettingUpEclipse. https://code.google.com/p/treeshaker/wiki/CreateNewScalaProject, August 2011. – abgerufenam: 15.08.2011

[Sha09] Sharkey, Google Developer Conference 2009 J.: Coding for Life – Bat-tery Life, That Is. http://www.google.com/intl/de-DE/events/io/2009/sessions/CodingLifeBatteryLife.html, Mai 2009. – abgerufenam: 07.09.2011

Sebastian Stallenberger81

Page 86: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Literaturverzeichnis Fachhochschule Schmalkalden SS 2011

[Sil11] Silva, Nelson: Scala on Android 101 - Proguard, XmlParser andFunction2AsyncTask. http://blog.nelsonsilva.eu/2009/10/31/scala-on-android-101-proguard-xmlparser-and-function2asynctask,August 2011. – abgerufen am: 28.08.2011

[Tom11] Tomshardware.de: Googles Android 4 kommt wahr-scheinlich im Oktober. http://www.tomshardware.de/Ice-Cream-Sandwich-Mango-iPhone-5-android-2.4-WP7,news-246059.html, August 2011. – abgerufen am: 11.08.2011

[Wik11] Wikipedia: Android (Betriebssystem). http://de.wikipedia.org/wiki/Android_%28Betriebssystem%29, August 2011. – abgerufen am:09.08.2011

Sebastian Stallenberger82

Page 87: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A Anhang

A.1 Tutorials für die Einrichtung vonEntwicklungsumgebungen

Hier finden sich Ergänzungen zum Kapitel 3 und ausführlichere Schritt-für-Schritt-Anleitungen zur Einrichtung von den Entwicklungsumgebungen mit Scala und An-droid.

A.1.1 Ergänzungen zur Einrichtung von SBT

Der Inhalt der *.bat-Datei lautet im Fall von SpiritMobile:

Listing A.1: Der Inhalt der bat-Datei.set SCRIPT_DIR=C:\ scalandroid \java -Xmx512M -jar "%SCRIPT_DIR %\sbt -launch -0.7.5. jar"

A.1.2 Einrichtung von Umgebungsvariablen

In Windows 7 findet man diese unter Systemsteuerung->System->Erweiterte Sys-temeinstellungen->Umgebungsvariablen1. Je nachdem, ob die Variablen für alle Nut-zer des Computers oder nur für den aktuellen Nutzer verfügbar sein sollen werdendie folgenden Änderungen im Feld Systemvariablen oder Benutzervariablen durch-geführt. Angegeben werden die Änderungen in Name=Wert-Paaren:

• SCALANDROID =C:\scalandroid• SCALA_HOME =%SCALANDROID%\scala-2.8.1.final• PATH2 = %JAVA_HOME%\bin; %SCALA_HOME%\bin;

%ANDROID_SDK_HOME%\tools; %SCALANDROID%• JAVA_HOME =%SCALANDROID%\jdk1.6.0_24• ANDROID_SDK_HOME =%SCALANDROID%\android-sdk-windows

Die Änderungen sind dann allerdings in bereits geöffneten Konsolen-Fenstern nochnicht verfügbar. Alternativ kann man sich auch auf der Konsole per set alle gesetz-ten Systemvariablen anzeigen lassen und per set variable=inhalt ändern oderanlegen.

1engl. „System Properties->System->Advanced System Setting-> Environment Variables“2falls vorhanden, bitte abgetrennt durch ein Semikolon erweitern

Sebastian Stallenberger83

Page 88: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

A.1.3 Konsole

Für die Nutzung des Scala-Android-Shellscripts unter Windows muss man folgendeSchritte durchführen, um das Script in eine ausführbare Scala-Datei umzuwandeln:

1. Datei create_project in einem Texteditor öffnen und die ersten drei Zeilen mit// auskommentieren. Anschließend speichern und schließen.

2. In der Konsole mit scala -deprecation create_project SpiritMobilede.fhs.spirit Script ausführen

Dies erzeugt im script-Ordner ein neues Verzeichnis namens SpiritMobile, das einAndroid-Scala-Dummy-Projekt beinhaltet. Die Verzeichnisstruktur folgt hierbei Ma-ven Konventionen. Anschließend wird das Verzeichnis manuell in C:\scalandroid\CODE kopiert.

A.1.4 Eclipse

In diesem Abschnitt werden fehlerhafte Methoden vorgestellt, Eclipse mit Androidund Scala zum Laufen zu bringen.Der erste Versuch sollte durch Umwandlung der SBT-Konfiguration in ein Eclipse-Projekt mit SbtEclipsify3 geschehen. Leider schlug dies fehl, aber der Autor stießauf eine andere Variante4 mittels ANT.Voraussetzung dafür ist ein vorkonfiguriertes Eclipse. Dabei geht man von einemsauberen „Eclipse Classic“ aus. Installiert als Plugins wurden:

• „Scala IDE for Eclipse 2.0.0 beta 3 for Scala 2.9.0.RC3“• ADT Plugin for Eclipse5

Bei der Installation des ADT Plugins kann ein Fehler auftreten, der wie folgt lautet:

Listing A.2: Mögliche Fehlermeldung bei der Installation des ADT Plugins.Cannot complete the install because one or more required

items could not be found.Software being installed : Android Development Tools

10.0.1. v201103111512 -110841 (com. android .ide. eclipse.adt. feature .group 10.0.1. v201103111512 -110841)

Missing requirement : Android Development Tools 10.0.1.v201103111512 -110841 (com. android .ide. eclipse .adt.feature .group 10.0.1. v201103111512 -110841) requires’org. eclipse .gef 0.0.0 ’ but it could not be found

Sollte dies der Fall sein, kann das Problem durch eine Installation des Plugins GEFSDK6 gelöst werden. Außerdem fehlt bei der blanken Eclipse-Version die Update-Sitehttp://download.eclipse.org/releases/helios. Diese sollte unter dem Namen „Helios“hinzugefügt werden.

3https://github.com/musk/SbtEclipsify4Vgl. http://www.assembla.com/wiki/show/scala-ide/Developing_for_Android5https://dl-ssl.google.com/android/eclipse/6Eclipse Update Adresse: http://download.eclipse.org/tools/gef/updates/releases/

Sebastian Stallenberger84

Page 89: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

In den Preferences muss der Pfad zum Android SDK angegeben werden. Anschlie-ßend erstellen wir ein neues Projekt „SpiritMobile“ in C:\scalandroid\CODE\SpiritMobile_Eclipse2. „SpiritMobile“ dient auch als Application name. Als Package namewurde de.fhs.spiritmobile, als Activity „main“ und als Min SDK-Version „8“ gewählt.Nach einem Klick auf „Next“ wird der Haken für die Erstellung eines Test-Projektsgesetzt und als Pfad C:\scalandroid\CODE\SpiritMobile_Eclipse2Test angegeben.Danach erstellt man die ANT-Files für das Projekt in der Konsole. Dazu navi-giert man in das Projektverzeichnis SpiritMobile_Eclipse2\src\main (da darin dieDatei AndroidManifest.xml liegt) und führt auf folgenden Befehl aus: androidupdate project -target 7 -path . 7 Dies erzeugt die Dateien build.properties,default.properties und build.xml im Projekt-Verzeichnis.In der Datei build.xml ersetzt man die Zeile <setup /> mit dem Code aus demangehängten Kapitel A.2. Unter Windows muss die Zeile -injars ${out.classes.absolute.dir}:tools/ in -injars ${out.classes.absolute.dir};tools/ um-geschrieben werden.Im nächsten Schritt erzeugt man ein Verzeichnis „tools“ im Projektordner. Dorthinein werden kopiert:

• proguard.rar8

• retrace.rar9

• scala-compiler.rar10

• scala-library.jarUm das Ant Script starten zu können muss noch der Ant-Pfad11 zur SystemvariablePath hinzugefügt werden. Eventuell muss vorher noch die neue Version von Antheruntergeladen werden, da das Android Ant-System erst ab Ant version 1.8 läuft.Gestartet werden sollte der Build-Prozess mit ant install. An dieser Stelle tratder Fehler „aaptexec doesn’t support the ‚basename‘ attribute“ mit dem packaging-Tool „aaptexec“ auf. Bei der Suche nach einer Lösung für dieses Problem stieß derAutor auf das treeshaker-Projekt, welches im Kapitel 3.3 erläutert wird.

A.1.5 IntelliJ

Das hier beschriebene Vorgehen bezieht sich auf die android-plugin-Version vomMärz 2011 und kann deshalb von aktuellen Anleitungen abweichen. Für die aktuelleVorgehensweise informieren Sie sich bitte auf der Website12 von android-plugin.Voraussetzung ist eine aktuelle IntelliJ-Installation und die Plugins Scala, SBT undAndroid. Das IntelliJ-Projekt basiert auf dem im Kapitel 3.2 erstellten SBT-Projektmithilfe des android-plugin. Die Quelle für dieses Kapitel ist [Bre11].

7Hierbei steht die 7 für die Android 2.2 Plattform ohne Google API. Die verfügbaren Plattformenkönnen über android list targets abgerufen werden.

8http://sourceforge.net/projects/proguard/files/9Ebenfalls im Proguard-Download enthalten

10Aus dem Ordner „C:\scalandroid\scala-2.8.1.final\lib“ kopiert11<eclipse-Pfad>\plugins\org.apache.ant_<versionsnummer>\bin12https://github.com/jberkel/android-plugin

Sebastian Stallenberger85

Page 90: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

1. In IntelliJ neues Java-Projekt aus vorhandenen Dateien erzeugen. Hierbei dasVerzeichnis des vorher erzeugten android-plugin-Projekts angeben. IntelliJ fin-det in $project_path/src/main/java source files. Im Fall des Autors wurdendie Dateien in $project_path/src_managed/main/java gefunden, was auf denVersions-Fehler mit dem android-plugin im Abschnitt Konsole zurückzuführenist.

2. Nach einem Klick auf Next sieht man die Libraries-Liste. Die library „lib“ wirdin „scala_2.9.0“ umbenannt.

3. Im nächsten Schritt benennt man das Modul Main in den Projektnamen, alsoin „SpiritMobile“ um.

4. Als Facet wählt man als nächstes „Android“ aus und beendet den Dialog mitKlick auf „Finish“. Das Projekt wird nun erstellt. Am Projektbaum müssenfolgende Änderungen vorgenommen werden.

5. Rechtsklick auf den Scala-Ordner und als Source Root markieren. Im Fall desAutors existierte dieser nicht im Baum. Das Kopieren der Ordner main undtest aus dem Ordner src in den Ordner src_managed löste dieses Problem.Zum Scala-Ordner wird jetzt noch das Package „de.fhs.spirit“ hinzugefügt.

6. Nachdem die Datei Activity.scala in MainActivity.scala umbenannt wurde,wird diese in das gerade erstellte Package verschoben. Dies war die letzteÄnderung am Dateibaum.

7. Rechtsklick auf das Projekt und „Open Module Settings“ wählen. Hier wähltman Facets, Android und danach Compiler

8. In der Sektion AAPT Compiler ändert man den Pfad $project_path/src/main/gen zu $project_path/src/main/java

9. In der Sektion Android Packaging Compiler wird der APK-Pfad in $pro-ject_path/target/scala_2.8.1/myproject_2.8.1-0.1.apk geändert.

10. Wenn noch nicht vorhanden, sollte unter Dependencies die im Schritt 3 um-benannte scala_2.9.0 hinzugefügt und deren Scope auf „Provided“ geändertwerden. Das waren die Änderungen in den Module Settings.

11. In File/Settings im Abschnitt „SBT“ wird der Pfad zur SBT launcher JARfile in C:\scalandroid\sbt-launch-0.7.7.jar geändert.

Das waren die Änderungen, die nötig sind, um das Projekt in IntelliJ einzubinden.Um es allerdings über Run starten zu können, muss noch eine Run-Konfigurationerstellt werden, die SBT nutzt.

1. Run/Edit Configurations2. Über das „+“ in der linken, oberen Ecke erstellt man eine neue „Android

application“ und ändert den Namen von „Unnamed“ in „DeployRun“.3. Man wählt aus dem Module drop down das Projekt aus und deaktiviert „Ma-

ke“.4. Dafür aktiviert man „Run Sbt Action“, trägt die Action „package-debug“ ein

und bestätigt die Dialoge jeweis mit OK.Jetzt kann man das Projekt über Run ausführen lassen. Das erstellte Paket wirdautomatisch auf den Emulator kopiert und gestartet. Das altbekannte „hello, world“

Sebastian Stallenberger86

Page 91: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

sollte auf dem Bildschirm erscheinen. Bei dieser Methode kann es vorkommen, dassfolgende Exception auftritt:

Listing A.3: Mögliche Fehlermeldung bei der Installation des android-plugin.[info] Compiling main sources ...[error] C:\ scalandroid \CODE\SpiritMobile - IntelliJ \

src_managed \main\java\de\fhs\spirit\R.java :10: R isalready defined as object R

[error] public final class R {[error] ^[error] one error found

Dieses Problem kommt daher, dass die R.java doppelt erzeugt wird. Sowohl imOrdner src/main/java als auch in src_managed\main\java. Um dieses Problem zuumgehen, kann in IntelliJ der Ordner src_managed aus dem Projekt ausgeschlos-sen werden. Sollte auch dies nicht helfen, kann man einfach die R.java im Ordnersrc/main/java vor jedem Compilieren gelöscht werden.

A.1.6 Manuelles Signieren anstatt ’prepare-market’

In dieser Anleitung steht „spiritmobile_2.9.0-0.1.2.apk“ für das zu signierende Paketund „spiritmobile-0.1.2-market.apk“ für das für den Market aufbereitete Paket.Der Keystore mit den Signatur-Daten nennt sich „stallenberger.keystore“ und liegtim gleichen Verzeichnis wie das zu signierende Paket. Im folgenden werden die be-nötigten Schritte anhand von Konsolenbefehlen aufgezeigt:

1. Der Befehl jarsigner -verify spiritmobile_2.9.0-0.1.2.apk sollte zurAusgabe „no manifest. jar is unsigned. (signatures missing or not parsable)“führen.

2. jarsigner -verbose -keystore stallenberger.keystore spiritmobile_2.9.0-0.1.2.apk spiritmobile13

3. Ein erneutes Ausführen von jarsigner -verify spiritmobile_2.9.0-0.1.2.apk sollte nun „jar verified.“ ausgeben

4. zipalign -v 4 spiritmobile_2.9.0-0.1.2.apk spiritmobile-0.1.2-market.apk

Danach ist das Paket für den Market gerüstet und kann hochgeladen werden.

13„spiritmobile“ ist hier der Name des Zertifikats im Keystore.

Sebastian Stallenberger87

Page 92: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

A.2 CodeIn diesem Kapitel findet sich Code, der nicht unmittelbar zu SpiritMobile gehört.Der folgende Code kommt aus der Quelle [ass11].

Listing A.4: Der Inhalt der buildExtension.<setup import="false" />

<!-- Custom tasks --><taskdef name=" aaptexec "

classname="com. android .ant. AaptExecLoopTask "classpathref =" android . antlibs " />

<taskdef name=" apkbuilder "classname="com. android .ant. ApkBuilderTask "classpathref =" android . antlibs " />

<taskdef name="xpath"classname="com. android .ant. XPathTask "classpathref =" android . antlibs " />

<!-- Properties -->

<!-- Tells adb which device to target. You can changethis from the command line

by invoking "ant -Dadb.device.arg=-d" for device "ant -Dadb.device.arg=-e" for

the emulator. --><property name="adb.device.arg" value="" />

<property name=" android .tools.dir" location="${ sdk.dir}/ tools" />

<!-- Name of the application package extracted frommanifest file -->

<xpath input=" AndroidManifest .xml" expression="/manifest /@package "

output=" manifest . package " />

<!-- Input directories --><property name="source.dir" value="src" /><property name="source. absolute .dir" location="${ source

.dir}" /><property name="gen.dir" value="gen" /><property name="gen. absolute .dir" location="${ gen.dir}"

/><property name=" resource .dir" value="res" /><property name=" resource . absolute .dir" location="${

resource .dir}" /><property name="asset.dir" value="assets" /><property name="asset. absolute .dir" location="${ asset.

dir}" />

<!-- Directory for the third party java libraries --><property name=" external .libs.dir" value="libs" />

Sebastian Stallenberger88

Page 93: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

<property name=" external .libs. absolute .dir" location="${ external .libs.dir}" />

<!-- Directory for the native libraries --><property name="native.libs.dir" value="libs" /><property name="native.libs. absolute .dir" location="${

native.libs.dir}" />

<!-- Output directories --><property name="out.dir" value="bin" /><property name="out. absolute .dir" location="${ out.dir}"

/><property name="out. classes .dir" value="${ out. absolute .

dir }/ classes " /><property name="out. classes . absolute .dir" location="${

out. classes .dir}" />

<!-- Intermediate files --><property name="dex.file.name" value=" classes .dex" /><property name=" intermediate .dex.file" location="${ out.

absolute .dir }/${ dex.file.name}" />

<!-- The final package file to generate --><property name="out.debug. unaligned . package "

location="${ out. absolute .dir }/${ ant.project .name}-debug - unaligned .apk" />

<property name="out.debug. package "location="${ out. absolute .dir }/${ ant.

project .name}-debug.apk" /><property name="out. unsigned . package "

location="${ out. absolute .dir }/${ ant.project .name}- unsigned .apk" />

<property name="out. unaligned . package "location="${ out. absolute .dir }/${ ant.

project .name}- unaligned .apk" /><property name="out. release . package "

location="${ out. absolute .dir }/${ ant.project .name}- release .apk" />

<!-- Verbosity --><property name=" verbose " value="false" /><!-- This is needed by emma as it uses multilevel

verbosity instead of simple ’true ’ or ’false ’The property ’verbosity ’ is not user configurable

and depends exclusively on ’verbose ’value.-->

<condition property=" verbosity " value=" verbose " else="quiet">

<istrue value="${ verbose }" /></ condition ><!-- This is needed to switch verbosity of zipalign and

aapt. Depends exclusively on ’verbose ’-->

<condition property="v.option" value="-v" else="">

Sebastian Stallenberger89

Page 94: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

<istrue value="${ verbose }" /></ condition ><!-- This is needed to switch verbosity of dx. Depends

exclusively on ’verbose ’ --><condition property=" verbose .option" value="--verbose "

else=""><istrue value="${ verbose }" />

</ condition >

<!-- Tools --><condition property="exe" value=".exe" else=""><os

family=" windows " /></ condition ><property name="adb" location="${ android .tools.dir }/ adb

${ exe}" /><property name=" zipalign " location="${ android .tools.dir

}/ zipalign ${ exe}" />

<!-- Emma configuration --><property name="emma.dir" value="${ sdk.dir }/ tools/lib"

/><path id="emma.lib">

<pathelement location="${ emma.dir }/ emma.jar" /><pathelement location="${ emma.dir }/ emma_ant.jar

" /></path >

<taskdef resource="emma_ant. properties " classpathref ="emma.lib" />

<!-- End of emma configuration -->

<!-- Macros -->

<!-- Configurable macro , which allows to pass asparameters output directory ,

output dex filename and external libraries to dex(optional) -->

<macrodef name="dex -helper"><element name="external -libs" optional="yes" /><element name="extra - parameters " optional="yes" /><sequential >

<echo >Converting compiled files and externallibraries into ${ intermediate .dex.file }...

</echo ><apply executable="${dx}" failonerror ="true"

parallel="true"><arg value="--dex" /><arg value="--output=${ intermediate .dex.file}"

/><extra - parameters /><arg line="${ verbose .option}" /><arg path="${ out. absolute .dir }/ classes .min.jar

" /><fileset dir="${ external .libs. absolute .dir}"

includes="*. min.jar" /><external -libs />

Sebastian Stallenberger90

Page 95: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

</apply ></ sequential >

</ macrodef >

<!-- This is macro that enable passing variable list ofexternal jar files to ApkBuilder

Example of use:<package -helper >

<extra -jars ><jarfolder path="my_jars" /><jarfile path="foo/bar.jar" /><jarfolder path="your_jars" />

</extra -jars ></package -helper > -->

<macrodef name="package -helper"><attribute name="sign. package " /><element name="extra -jars" optional="yes" /><sequential >

<apkbuilderoutfolder="${ out. absolute .dir}"resourcefile ="${ ant. project .name }.ap_

"apkfilepath ="${ out.debug. unaligned .

package }"debug="${ build.debug}"abifilter="${ filter.abi}"verbose="${ verbose }"hascode="true">

<dex path="${ intermediate .dex.file}"/><sourcefolder path="${ source. absolute .dir

}"/><sourcefolder refid=" android . libraries .

src"/><jarfolder path="${ external .libs. absolute

.dir}" /><jarfolder refid=" android . libraries .libs"

/><nativefolder path="${ native.libs.

absolute .dir}" /><nativefolder refid=" android . libraries .

libs" /><extra -jars/>

</ apkbuilder >

</ sequential ></ macrodef >

<!-- This is macro which zipaligns in.package andoutputs it to out.package. Used by targets

debug , -debug -with -emma and release.--><macrodef name="zipalign -helper">

<attribute name="in. package " /><attribute name="out. package " /><sequential >

Sebastian Stallenberger91

Page 96: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

<echo >Running zip align on final apk ... </echo ><exec executable="${ zipalign }" failonerror ="

true"><arg line="${v.option}" /><arg value="-f" /><arg value="4" /><arg path="@{in. package }" /><arg path="@{out. package }" />

</exec ></ sequential >

</ macrodef >

<!-- This is macro used only for sharing code among twotargets , -install and

-install -with -emma which do exactly the same butdiffer in dependencies -->

<macrodef name="install -helper"><sequential >

<echo >Installing ${ out.debug. package } ontodefault emulator or device ... </echo >

<exec executable="${ adb}" failonerror ="true"><arg line="${ adb.device.arg}" /><arg value=" install " /><arg value="-r" /><arg path="${ out.debug. package }" />

</exec ></ sequential >

</ macrodef >

<!-- Rules -->

<!-- Creates the output directories if they don’t existyet. -->

<target name="-dirs"><echo > Creating output directories if needed ... </

echo ><mkdir dir="${ resource . absolute .dir }" /><mkdir dir="${ external .libs. absolute .dir }" /><mkdir dir="${ gen. absolute .dir }" /><mkdir dir="${ out. absolute .dir }" /><mkdir dir="${ out. classes . absolute .dir }" />

</target >

<!-- Generates the R.java file for this project ’sresources. -->

<target name="-resource -src" depends="-dirs"><echo >Generating R.java / Manifest .java from the

resources ... </echo ><exec executable="${ aapt}" failonerror ="true">

<arg value=" package " /><arg line="${v.option}" /><arg value="-m" /><arg value="-J" /><arg path="${ gen. absolute .dir}" />

Sebastian Stallenberger92

Page 97: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

<arg value="-M" /><arg path=" AndroidManifest .xml" /><arg value="-S" /><arg path="${ resource . absolute .dir}" /><arg value="-I" /><arg path="${ android .jar}" />

</exec ></target >

<!-- Generates java classes from .aidl files. --><target name="-aidl" depends="-dirs">

<echo >Compiling aidl files into Java classes ... </echo >

<apply executable="${ aidl}" failonerror ="true"><arg value="-p${ android .aidl}" /><arg value="-I${ source. absolute .dir}" /><arg value="-o${ gen. absolute .dir}" /><fileset dir="${ source. absolute .dir}">

<include name="**/*. aidl" /></ fileset >

</apply ></target >

<!-- Compiles this project ’s .java files into .classfiles. -->

<target name=" compile " depends="-resource -src , -aidl"description =" Compiles project ’s .java files

into .class files"><!-- If android rules are used for a test project ,

its classpath should includetested project ’s location -->

<condition property="extensible.classpath"value="${ tested.project.absolute

.dir}/bin/classes" else="."><isset property="tested.project.absolute.dir"

/></condition >

<javac encoding="ascii" target="1.5" debug="true"extdirs=""

destdir="${out.classes.absolute.dir}"bootclasspathref ="android.target.classpath"verbose="${ verbose}" classpath="${

extensible.classpath}"><src path="${ source.absolute.dir}" /><src path="${gen.absolute.dir}" /><classpath >

<fileset dir="${ external.libs.absolute.dir}" includes="*.jar" />

</classpath ></javac >

<taskdef resource="scala/tools/ant/antlib.xml"classpath="tools/scala -compiler.jar:tools/scala -

Sebastian Stallenberger93

Page 98: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

library.jar" /><scalac force="changed" deprecation ="on"

destdir="${out.classes.absolute.dir}"bootclasspathref ="android.target.classpath">

<src path="${ source.absolute.dir}" /><src path="${gen.absolute.dir}" />

<classpath ><fileset dir="${ external.libs.absolute.dir}"

includes="*.jar" /><fileset dir="tools" includes="*.jar"/>

</classpath ></scalac >

</target >

<target name="proguard" depends="compile"><taskdef resource="proguard/ant/task.properties"

classpath="tools/proguard.jar" /><proguard >

-injars ${ out. classes . absolute .dir}:tools/scala -library .jar (!META -INF/ MANIFEST .MF ,! library .properties )

-outjars "${out.absolute.dir}/ classes.min.jar"-libraryjars "${ android.jar}"-dontwarn-dontoptimize-dontobfuscate-keep public class * extends android .app. Activity

</proguard ></target >

<!-- Converts this project ’s .class files into .dexfiles -->

<target name="-dex" depends="proguard"><dex -helper />

</target >

<!-- Puts the project ’s resources into the outputpackage file

This actually can create multiple resource packagein case

Some custom apk with specific configuration havebeen

declared in default . properties .-->

<target name="-package -resources"><echo > Packaging resources </echo ><aaptexec executable="${aapt}"

command="package"manifest="AndroidManifest.xml"resources="${ resource.absolute.dir}"assets="${asset.absolute.dir}"androidjar="${ android.jar}"outfolder="${out.absolute.dir}"

Sebastian Stallenberger94

Page 99: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

basename="${ant.project.name}" /></target >

<!-- Packages the application and sign it with a debugkey. -->

<target name="-package -debug -sign" depends="-dex , -package -resources">

<package -helper sign. package="true" /></target >

<!-- Packages the application without signing it. --><target name="-package -no-sign" depends="-dex , -package

-resources"><package -helper sign. package="false" />

</target >

<target name="-compile -tested -if-test" if="tested.project.dir" unless="do.not.compile.again"><subant target="compile">

<fileset dir="${ tested.project.absolute.dir}"includes="build.xml" />

</subant ></target >

<!-- Builds debug output package , provided all thenecessary files are already dexed -->

<target name="debug" depends="-compile -tested -if-test ,-package -debug -sign"

description ="Builds the application andsigns it with a debug key.">

<zipalign -helper in. package="${out.debug.unaligned.package}"

out. package="${out.debug.package}" />

<echo >Debug Package: ${ out.debug. package }</echo ></target >

<target name="-release -check"><condition property="release.sign">

<and ><isset property="key.store" /><isset property="key.alias" />

</and ></condition >

</target >

<target name="-release -nosign" depends="-release -check"unless="release.sign"><echo >No key.store and key.alias properties found

in build. properties .</echo ><echo >Please sign ${ out. unsigned . package } manually

</echo ><echo >and run zipalign from the Android SDK tools

.</echo >

Sebastian Stallenberger95

Page 100: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

</target >

<target name="release" depends="-package -no-sign , -release -nosign" if="release.sign"

description ="Builds the application. Thegenerated apk file must be signed before

it is published."><!-- Gets passwords --><input

message="Please enter keystore password (store:${key.store}):"

addproperty ="key.store.password" /><input

message="Please enter password for alias ’${ key.alias}’:"

addproperty ="key.alias.password" />

<!-- Signs the APK --><echo > Signing final apk ... </ echo ><signjar

jar="${out.unsigned.package}"signedjar="${out.unaligned.package}"keystore="${key.store}"storepass="${key.store.password}"alias="${key.alias}"keypass="${key.alias.password}"verbose="${ verbose}" />

<!-- Zip aligns the APK -->

<zipalign -helper in. package="${out.unaligned.package}"

out. package="${out.release.package}" />

<echo > Release Package: ${ out. release . package }</echo>

</target >

<target name="install" depends="debug"description ="Installs/reinstalls the debug

package onto a runningemulator or device. If the

application was previouslyinstalled ,

the signatures must match." ><install -helper />

</target >

<target name="-uninstall -check"><condition property="uninstall.run">

<isset property="manifest.package" /></condition >

</target >

Sebastian Stallenberger96

Page 101: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

<target name="-uninstall -error" depends="-uninstall -check" unless="uninstall.run">

<echo >Unable to run ’ant uninstall ’, manifest .package property is not defined .

</echo ></target >

<!-- Uninstalls the package from the default emulator /device -->

<target name="uninstall" depends="-uninstall -error" if="uninstall.run"

description ="Uninstalls the applicationfrom a running emulator or device.">

<echo > Uninstalling ${ manifest . package } from thedefault emulator or device ... </ echo >

<exec executable="${adb}" failonerror ="true"><arg line="${adb.device.arg}" /><arg value="uninstall" /><arg value="${ manifest.package}" />

</exec ></target >

<target name="clean" description ="Removes output filescreated by other targets.">

<delete dir="${out.absolute.dir}" verbose="${verbose}" />

<delete dir="${gen.absolute.dir}" verbose="${verbose}" />

</target >

<!-- Targets for code - coverage measurement purposes ,invoked from external file -->

<!-- Emma - instruments tested project classes ( compilesthe tested project if necessary )

and writes instrumented classes to ${instrumentation . absolute .dir }/ classes -->

<target name="-emma -instrument" depends="compile"><echo > Instrumenting classes from ${ out. absolute .dir

}/ classes ... </ echo ><!-- It only instruments class files , not any

external libs --><emma enabled="true">

<instr verbosity="${ verbosity}"mode="overwrite"instrpath="${out.absolute.dir}/ classes"outdir="${out.absolute.dir}/ classes">

</instr ><!-- TODO: exclusion filters on R*. class and

allowing custom exclusion fromuser defined file -->

</emma ></target >

Sebastian Stallenberger97

Page 102: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

<target name="-dex -instrumented" depends="-emma -instrument"><dex -helper >

<extra -parameters ><arg value="--no -locals" />

</extra -parameters ><external -libs >

<fileset file="${ emma.dir }/ emma_device.jar" /></external -libs >

</dex -helper ></target >

<!-- Invoked from external files for code coveragepurposes -->

<target name="-package -with -emma" depends="-dex -instrumented , -package - resources ">

<package -helper sign. package="true"><extra -jars >

<!-- Injected from external file --><jarfile path="${ emma.dir }/ emma_device.jar"

/></extra -jars >

</package -helper ></target >

<target name="-debug -with -emma" depends="-package -with -emma">

<zipalign -helper in. package="${ out.debug. unaligned .package }"

out. package="${ out.debug. package }" />

</target >

<target name="-install -with -emma" depends="-debug -with -emma">

<install -helper /></target >

<!-- End of targets for code - coverage measurementpurposes -->

<target name="help"><!-- displays starts at col 13

|13

80| --><echo > Android Ant Build. Available targets: </echo ><echo > help: Displays this help .</echo ><echo > clean: Removes output files created by

other targets .</echo ><echo > compile: Compiles project ’s .java files

into .class files .</echo ><echo > debug: Builds the application and

signs it with a debug key.</echo >

Sebastian Stallenberger98

Page 103: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

A. Anhang Fachhochschule Schmalkalden SS 2011

<echo > release: Builds the application . Thegenerated apk file must be </echo >

<echo > signed before it is published.</echo >

<echo > install: Installs / reinstalls the debugpackage onto a running </echo >

<echo > emulator or device .</echo ><echo > If the application was

previously installed , the </echo ><echo > signatures must match .</echo ><echo > uninstall: Uninstalls the application from

a running emulator or </echo ><echo > device .</echo >

</target >

A.3 IconsDie Icons in SpiritMobile stehen alle unter der GNU LESSER GENERAL PUBLICLICENSE.Die Quellen sind:http :// www. iconfinder .com/ icondetails /6634/128/

calendar_date_event_plan_iconhttp :// www. iconfinder .com/ icondetails /18421/128/

latest_news_news_paper_newsletter_iconhttp :// www. iconfinder .com/ icondetails /18171/128/

editors_package_iconhttp :// www. iconfinder .com/ icondetails /18242/128/

vcalendar_iconhttp :// www. iconfinder .com/ icondetails /6694/128/ tools_iconhttp :// www. iconfinder .com/ icondetails /6843/128/

developer_folder_iconhttp :// www. iconfinder .com/ icondetails /6712/128/

human_person_user_iconhttp :// www. iconfinder .com/ icondetails /6083/128/

group_jabber_iconhttp :// www. iconfinder .com/ icondetails /6071/128/ help_icon

Sebastian Stallenberger99

Page 104: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Abbildungsverzeichnis

2.1 Die Android Achitektur in Anlehnung an [BP10, Abb. 2-1] und [Goo11j] 62.2 Der Weg vom Java- zum Dex-Bytecode in Anlehnung an [BP10] Abb.

2-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72.3 Die verfügbaren SDK-Umgebungen im Versionsvergleich in Anleh-

nung an [Goo11e] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.4 Die Unterteilung einer NinePatch-Grafik in Anlehnung an [Dar10] . . 102.5 Der Hierarchy Viewer . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

5.1 Möglichkeiten der Nutzer-Navigation durch die Module . . . . . . . . 215.2 Vorschläge zur Anordnung der Menü-Elemente . . . . . . . . . . . . . 225.3 Aufbau von NewsMulti und der einzelnen News-Elemente . . . . . . . 235.4 Aufbau von NewsSingle, des Comment-Blocks und eines einzelnen

Comment-Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255.5 Aufbau von NewsCreate . . . . . . . . . . . . . . . . . . . . . . . . . 265.6 Aufbau des TimeTable in vertikaler und horizontaler Lage . . . . . . 275.7 Aufbau der Detailansicht eines Timeslots . . . . . . . . . . . . . . . . 285.8 Aufbau von Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . 285.9 Abruf-Algorithmus in NewsMulti . . . . . . . . . . . . . . . . . . . . 295.10 Algorithmus des Sendens einer News . . . . . . . . . . . . . . . . . . 30

6.1 Lebenszyklus einer Activity in Anlehnung an [Goo11a] . . . . . . . . 356.2 Screenshot der Activity MainActivity mit geöffnetem Optionsmenü . 436.3 Screenshot der PreferenceActivity Settings . . . . . . . . . . . . . . . 61

Sebastian Stallenberger100

Page 105: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Tabellenverzeichnis

1.1 Verbreitung aktueller Android-Versionen in Anlehnung an [Goo11g] . 3

Sebastian Stallenberger101

Page 106: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Listings

3.1 Die Verzeichnisstruktur des mit android-plugin erzeugten Projekts. . 16

6.1 Die ersten zwei Zeilen eines AsyncTasks in Java. Quelle: [Goo11d] . . 336.2 Die AsyncTask Wrapper-Klasse in Anlehnung an [Sil11] . . . . . . . . 336.3 Code des AsyncTask NewsReloadTask . . . . . . . . . . . . . . . . . 346.4 Die Methoden onCreate und onResume der MainActivity . . . . . . . 366.5 Der Code für den Aufbau des Beta-Screens (Teil 1) . . . . . . . . . . 376.6 Der Code für den Aufbau des Beta-Screens (Teil 2) . . . . . . . . . . 386.7 Der Code für den Aufbau des Beta-Screens (Teil 3) . . . . . . . . . . 396.8 Die Abfrage der Rolle und die Definition des Menü-Arrays. . . . . . . 396.9 Die Verbindung zwischen dataList und der GridView. . . . . . . . . . 406.10 Die Methode menuHandler. . . . . . . . . . . . . . . . . . . . . . . . 406.11 Der MainMenuAdapter. . . . . . . . . . . . . . . . . . . . . . . . . . 416.12 Auszüge aus der Klasse MainMenuAdapter. . . . . . . . . . . . . . . 416.13 Der Aufbau eines Optionsmenü (Teil 1) . . . . . . . . . . . . . . . . . 436.14 Der Aufbau eines Optionsmenü (Teil 2) . . . . . . . . . . . . . . . . . 436.15 Der Aufbau eines Optionsmenü (Teil 3) . . . . . . . . . . . . . . . . . 446.16 Inhalt der onCreate-Methode von NewsMulti . . . . . . . . . . . . . . 446.17 Die Methode checkInternetConnection in SpiritConnect . . . . . . . . 456.18 Die Methode constructNewsMultiMainLay in ViewBuilder . . . . . . 456.19 Die Konstruktion einer einzelnen News in der Funktion ViewBuil-

der.buildNewsView (Teil 1) . . . . . . . . . . . . . . . . . . . . . . . 466.20 Die Konstruktion einer einzelnen News in der Funktion ViewBuil-

der.buildNewsView (Teil 2) . . . . . . . . . . . . . . . . . . . . . . . 466.21 Die Konstruktion einer einzelnen News in der Funktion ViewBuil-

der.buildNewsView (Teil 3) . . . . . . . . . . . . . . . . . . . . . . . 476.22 Die Methode onActivityResult in NewsMulti . . . . . . . . . . . . . . 486.23 Der Inhalt des onClick-Events einer News in NewsMulti . . . . . . . . 496.24 Die Activity NewsSingle . . . . . . . . . . . . . . . . . . . . . . . . . 506.25 Die Methode buildCommentsView zur Konstruktion der Kommentar-

Liste. (Teil 1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516.26 Die Methode buildCommentsView zur Konstruktion der Kommentar-

Liste. (Teil 2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516.27 Die Methode buildCommentsView zur Konstruktion der Kommentar-

Liste. (Teil 3) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526.28 Auszüge aus dem Task NewsCommentCreateTask. . . . . . . . . . . . 526.29 Auszüge aus dem Task NewsLoadSingleTask. . . . . . . . . . . . . . . 526.30 Die Datei newscreate.xml mit dem Layout für die Activity NewsCreate. 536.31 Auszug aus der Activity NewsCreate. . . . . . . . . . . . . . . . . . . 54

Sebastian Stallenberger102

Page 107: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Listings Fachhochschule Schmalkalden SS 2011

6.32 Laden der für den DegreeClass-Dialog benötigten Daten. . . . . . . . 556.33 Setzen der onClick-Events für die GUI-Elemente. (Teil 1) . . . . . . . 566.34 Setzen der onClick-Events für die GUI-Elemente. (Teil 2) . . . . . . . 566.35 Die Methode translateDegreeNameToId. . . . . . . . . . . . . . . . . 576.36 Die Methode onCreateDialog. . . . . . . . . . . . . . . . . . . . . . . 576.37 Die Methode returnSelectedDegrees. . . . . . . . . . . . . . . . . . . 586.38 Der Listener mDateSetListener. . . . . . . . . . . . . . . . . . . . . . 596.39 Die XML-Datei für die Settings. . . . . . . . . . . . . . . . . . . . . . 606.40 Die PreferenceActivity Settings. (Teil 1) . . . . . . . . . . . . . . . . 616.41 Die PreferenceActivity Settings. (Teil 2) . . . . . . . . . . . . . . . . 626.42 Die PreferenceActivity Settings. (Teil 3) . . . . . . . . . . . . . . . . 636.43 Die doInBackground-Methode des Tasks VerifyLoginDataTask. . . . . 646.44 Der Inhalt der info.xml. . . . . . . . . . . . . . . . . . . . . . . . . . 646.45 Der Inhalt der onCreate-Methode der Activity Info. . . . . . . . . . . 656.46 Die Methode readTextFromResource. . . . . . . . . . . . . . . . . . . 656.47 Die Case Classes im Objekt JSON-Processor. . . . . . . . . . . . . . . 666.48 Die Methode jsonStringToSingleNews. . . . . . . . . . . . . . . . . . 676.49 Die Klasse SpiritHttpClient. . . . . . . . . . . . . . . . . . . . . . . . 686.50 Die Methode getJsonFromUrl. . . . . . . . . . . . . . . . . . . . . . . 696.51 Die Methode putJsonToUrl. . . . . . . . . . . . . . . . . . . . . . . . 706.52 Die Methode checkInternetConnection. . . . . . . . . . . . . . . . . . 706.53 Die Methode getNews. . . . . . . . . . . . . . . . . . . . . . . . . . . 716.54 Die Methode convertStreamToString. . . . . . . . . . . . . . . . . . . 726.55 Die Methoden loadString und saveString. . . . . . . . . . . . . . . . . 726.56 Die Methoden setStringPrefs und getStringPrefs. . . . . . . . . . . . 736.57 Die Methode getBoolPrefs. . . . . . . . . . . . . . . . . . . . . . . . . 736.58 Die Methode setLastNewsDate. . . . . . . . . . . . . . . . . . . . . . 746.59 Die Methode getDegreeMap. . . . . . . . . . . . . . . . . . . . . . . . 74

A.1 Der Inhalt der bat-Datei. . . . . . . . . . . . . . . . . . . . . . . . . . 83A.2 Mögliche Fehlermeldung bei der Installation des ADT Plugins. . . . . 84A.3 Mögliche Fehlermeldung bei der Installation des android-plugin. . . . 87A.4 Der Inhalt der buildExtension. . . . . . . . . . . . . . . . . . . . . . . 88

Sebastian Stallenberger103

Page 108: Entwicklung einer auf Scalabasierenden Android-Applikation fürdas Hochschul-InformationssystemSpirit der Fakultät Informatik an derFachhochschule Schmalkalden

Eidesstattliche ErklärungIch versichere an Eides Statt durch meine eigenhändige Unterschrift, dass ich dievorliegende Arbeit selbstständig und ohne fremde Hilfe angefertigt habe. Alle Stel-len, die wörtlich oder dem Sinn nach auf Publikationen oder Vorträgen andererAutoren beruhen, sind als solche kenntlich gemacht. Ich versichere außerdem, dassich keine andere als die angegebene Literatur verwendet habe. Diese Versicherungbezieht sich auch auf alle in der Arbeit enthaltenen Zeichnungen, Skizzen, bildlichenDarstellungen und dergleichen.

Die Arbeit wurde bisher keiner anderen Prüfungsbehörde vorgelegt und auch nochnicht veröffentlicht.

Bad Neustadt,den 7. Oktober 2011

Ort, Datum Sebastian Stallenberger

Sebastian Stallenberger104