Android 3 - Apps entwickeln mit dem Android SDK

Natürlich finden Sie alle Programme als Eclipse-Pro- jekte auch auf ... ten ein neues Projekt anlegen, erzeugen die Android Development Tools eine minimale ...
2MB Größe 4 Downloads 463 Ansichten
Thomas Künneth

Android 3 Apps entwickeln mit dem Android SDK

Auf einen Blick TEIL I

Grundlagen

1

Android – eine offene, mobile Plattform ...............................

19

2

Hallo Android! .....................................................................

35

3

Von der Idee zur Veröffentlichung ........................................

59

TEIL II Elementare Anwendungsbausteine 4

Activities und Broadcast Receiver .........................................

85

5

Benutzeroberflächen ............................................................

113

6

Multitasking .........................................................................

147

TEIL III Telefonfunktionen nutzen 7

Rund ums Telefonieren ........................................................

171

8

Widgets und Wallpapers ......................................................

181

9

Sensoren und GPS ................................................................

209

TEIL IV Dateien und Datenbanken 10 Das Android-Dateisystem .....................................................

233

11 Datenbanken .......................................................................

251

12 Content Provider ..................................................................

271

13 Live Folder ...........................................................................

291

TEIL V Organizer und Multimedia 14 Audio ...................................................................................

307

15 Fotos und Video ..................................................................

339

16 Kontakte und Organizer .......................................................

369

Inhalt Vorwort ........................................................................................................

13

TEIL I Grundlagen 1

Android – eine offene, mobile Plattform ................................. 19 1.1

1.2

1.3

2

19 20 20 21 23 23 25 26 27 28 32 33

Hallo Android! .......................................................................... 35 2.1

2.2

2.3

3

Entstehung .................................................................................. 1.1.1 Die Open Handset Alliance ............................................. 1.1.2 Android Inc. .................................................................... 1.1.3 Evolution einer Plattform ................................................ Systemarchitektur ........................................................................ 1.2.1 Überblick ........................................................................ 1.2.2 Android Runtime ............................................................ 1.2.3 Application Framework ................................................... Entwicklungswerkzeuge ............................................................... 1.3.1 Android SDK ................................................................... 1.3.2 Android Development Tools ........................................... 1.3.3 Das erste eigene Projekt ..................................................

Android-Projekte ......................................................................... 2.1.1 Projekte anlegen ............................................................. 2.1.2 Projektstruktur ................................................................ 2.1.3 Run Configurations ......................................................... Die Benutzeroberfläche ............................................................... 2.2.1 Texte ............................................................................... 2.2.2 Views .............................................................................. 2.2.3 Oberflächenbeschreibungen ............................................ Programmlogik und -ablauf .......................................................... 2.3.1 Activities ......................................................................... 2.3.2 Benutzereingaben ........................................................... 2.3.3 Der letzte Schliff ..............................................................

35 35 37 40 43 44 47 48 50 51 54 55

Von der Idee zur Veröffentlichung ........................................... 59 3.1

Konzept und Realisierung ............................................................ 3.1.1 Konzeption .....................................................................

59 60

7

Inhalt

3.2

3.3

3.1.2 Fachlogik ........................................................................ 3.1.3 Benutzeroberfläche ......................................................... Vom Programm zum Produkt ....................................................... 3.2.1 Protokollierung ............................................................... 3.2.2 Fehler suchen und finden ................................................ 3.2.3 Debuggen auf echter Hardware ....................................... Anwendungen verteilen ............................................................... 3.3.1 Verteilbare Anwendungen ............................................... 3.3.2 Apps im Android Market einstellen ................................. 3.3.3 Alternative Märkte und Ad hoc-Verteilung ......................

61 64 69 70 73 75 76 77 79 81

TEIL II Elementare Anwendungsbausteine 4

Activities und Broadcast Receiver ........................................... 85 4.1

4.2

4.3

5

85 85 92 99 99 101 103 107 107 110

Benutzeroberflächen ................................................................ 113 5.1

5.2

5.3

8

Was sind Activities? ..................................................................... 4.1.1 Struktur von Apps ........................................................... 4.1.2 Lebenszyklus von Activities ............................................. Kommunikation zwischen Anwendungsbausteinen ...................... 4.2.1 Intents ............................................................................ 4.2.2 Kommunikation zwischen Activities ................................ 4.2.3 Broadcast Receiver .......................................................... Fragmente ................................................................................... 4.3.1 Grundlagen ..................................................................... 4.3.2 Ein Fragment in eine Activity einbetten ...........................

Views und ViewGroups ................................................................ 5.1.1 Views .............................................................................. 5.1.2 Positionierung von Bedienelementen mit ViewGroups .... Alternative Ressourcen ................................................................ 5.2.1 Automatische Layout-Auswahl ........................................ 5.2.2 Bitmaps und Pixeldichte .................................................. Vorgefertigte Bausteine für Oberflächen ...................................... 5.3.1 Nützliche Activities ......................................................... 5.3.2 Dialoge ........................................................................... 5.3.3 Menüs ............................................................................

113 114 120 126 126 132 133 133 139 143

Inhalt

6

Multitasking ............................................................................. 147 6.1

6.2

Threads ....................................................................................... 6.1.1 Threads in Java ................................................................ 6.1.2 Vom Umgang mit Threads in Android ............................. Services ....................................................................................... 6.2.1 Gestartete Services .......................................................... 6.2.2 Gebundene Services ........................................................

148 148 152 156 156 160

TEIL III Telefonfunktionen nutzen 7

Rund ums Telefonieren ............................................................ 171 7.1

7.2

7.3

8

171 171 173 175 175 176 176 177 178 179

Widgets und Wallpapers ......................................................... 181 8.1

8.2

8.3

9

Telefonieren ................................................................................ 7.1.1 Anrufe tätigen ................................................................. 7.1.2 Auf eingehende Anrufe reagieren .................................... Telefon- und Netzstatus ............................................................... 7.2.1 Geräte identifizieren ........................................................ 7.2.2 Netzwerkinformationen anzeigen .................................... Das Call Log ................................................................................. 7.3.1 Entgangene Anrufe .......................................................... 7.3.2 Einträge bearbeiten ......................................................... 7.3.3 Benachrichtigung bei Änderungen ...................................

Widgets ....................................................................................... 8.1.1 Beteiligte Klassen und Dateien ........................................ 8.1.2 Die Benutzeroberfläche ................................................... Wallpaper .................................................................................... 8.2.1 Die Wallpaper-API .......................................................... 8.2.2 Hintergründe auswählen ................................................. Live Wallpaper ............................................................................. 8.3.1 WallpaperService und Engine .......................................... 8.3.2 Live Wallpaper auswählen ............................................... 8.3.3 Einstellungsseiten ............................................................

181 182 187 190 190 192 196 197 202 205

Sensoren und GPS .................................................................... 209 9.1

Sensoren ...................................................................................... 209 9.1.1 Die Klasse SensorManager .............................................. 209 9.1.2 Sensoren simulieren ........................................................ 212

9

Inhalt

9.2

GPS und ortsbezogene Dienste .................................................... 219 9.2.1 Den aktuellen Standort ermitteln .................................... 220 9.2.2 Positionen in einer Karte anzeigen .................................. 225

TEIL IV Dateien und Datenbanken 10 Das Android-Dateisystem ........................................................ 233 10.1

10.2

Grundlegende Dateioperationen .................................................. 10.1.1 Dateien lesen und schreiben ........................................... 10.1.2 Mit Verzeichnissen arbeiten ............................................ Externe Speichermedien .............................................................. 10.2.1 Mit SD-Cards arbeiten ..................................................... 10.2.2 Installationsort von Apps .................................................

233 234 239 243 243 247

11 Datenbanken ............................................................................ 251 11.1

11.2

Erste Schritte mit SQLite .............................................................. 11.1.1 Was ist SQLite? ............................................................... 11.1.2 Auf der Kommandozeile arbeiten .................................... 11.1.3 SQLite in Apps nutzen ..................................................... Fortgeschrittene Operationen ...................................................... 11.2.1 Klickverlauf mit SELECT ermitteln .................................... 11.2.2 Daten mit UPDATE ändern und mit DELETE löschen .......

251 252 253 256 262 263 268

12 Content Provider ...................................................................... 271 12.1

12.2

Vorhandene Content Provider nutzen .......................................... 12.1.1 Mit Content Resolver auf Wörterbücher zugreifen ........... 12.1.2 Browser-Bookmarks ........................................................ Implementierung eines eigenen Content Providers ...................... 12.2.1 Anpassungen an der App TKMoodley .............................. 12.2.2 Die Klasse android.content.ContentProvider ...................

272 272 276 279 279 284

13 Live Folder ................................................................................ 291 13.1

13.2

10

Die Benutzeroberfläche ............................................................... 13.1.1 Einen Live Folder anlegen ............................................... 13.1.2 Beteiligte Klassen und Dateien ........................................ Das Backend ................................................................................ 13.2.1 Content Provider ............................................................. 13.2.2 Ein eigener Cursor ...........................................................

291 291 294 297 297 299

Inhalt

TEIL V Organizer und Multimedia 14 Audio ........................................................................................ 307 14.1

14.2

14.3

14.4

Rasender Reporter – ein Diktiergerät als App ............................... 14.1.1 Struktur der App ............................................................. 14.1.2 Audio aufnehmen und abspielen ..................................... Effekte ......................................................................................... 14.2.1 Die Klasse AudioEffekteDemo ......................................... 14.2.2 Bass Boost und Virtualizer ............................................... 14.2.3 Hall ................................................................................. Sprachsynthese ............................................................................ 14.3.1 Nutzung der Sprachsynthesekomponente vorbereiten ..... 14.3.2 Texte vorlesen ................................................................. 14.3.3 Sprachausgaben speichern ............................................... Weitere Audiofunktionen ............................................................ 14.4.1 Spracherkennung ............................................................ 14.4.2 Tastendrücke von Headsets verarbeiten ...........................

307 307 310 316 316 319 321 322 323 327 329 330 330 334

15 Fotos und Video ....................................................................... 339 15.1

15.2

15.3

Vorhandene Activities nutzen ...................................................... 15.1.1 Kamera-Activity starten ................................................... 15.1.2 Aufgenommene Fotos weiterverarbeiten ......................... 15.1.3 Mit der Galerie arbeiten .................................................. 15.1.4 Die Kamera-App erweitern ............................................. Die eigene Kamera-App ............................................................... 15.2.1 Live-Vorschau ................................................................. 15.2.2 Kamera auswählen .......................................................... 15.2.3 Fotos aufnehmen ............................................................ Videos drehen ............................................................................. 15.3.1 Die App VideoCaptureDemo ........................................... 15.3.2 MediaRecorder konfigurieren ..........................................

339 339 342 346 348 353 353 357 359 362 362 366

16 Kontakte und Organizer .......................................................... 369 16.1

Kontakte ...................................................................................... 16.1.1 Eine einfache Kontaktliste ausgeben ................................ 16.1.2 Weitere Kontaktdaten ausgeben ..................................... 16.1.3 Geburtstage hinzufügen und aktualisieren .......................

369 369 372 374

11

Inhalt

16.2

16.3

Auf Google-Konten zugreifen ...................................................... 16.2.1 Emulator konfigurieren .................................................... 16.2.2 Aufgabenliste auslesen .................................................... Kalender und Termine ................................................................. 16.3.1 Termine anlegen und auslesen ........................................ 16.3.2 Alarme verwalten ............................................................ 16.3.3 Der Kalender-Content-Provider .......................................

380 381 384 389 389 391 395

Anhang ........................................................................................... 399 A B C

Literaturverzeichnis ................................................................................ Die Begleit-DVD .................................................................................... Häufig benötigte Code-Bausteine ........................................................... C.1 Manifestdatei .............................................................................. C.2 Berechtigungen ........................................................................... C.2.1 Hardware, Telefonie und Netzwerk ................................. C.2.2 Internet ........................................................................... C.2.3 Audio und Video ............................................................. C.2.4 Kontakte und Kalender ...................................................

401 403 407 407 408 408 409 409 410

Index ............................................................................................................ 411

12

Vorwort

Als die Deutsche Telekom Anfang 2009 das Google G1 vorstellte, war die Neugier groß. Ein Handy des Suchmaschinenprimus ließ auf eine enge Integration seiner Dienste und damit auf viele spannende, neue Möglichkeiten hoffen. Dass das erste Android-Smartphone die hoch gesteckten Erwartungen noch nicht ganz erfüllen konnte, darf angesichts eines scheinbar übermächtigen Konkurrenten nicht verwundern. Apple hatte seit der Einführung des iPhone akribisch und zielstrebig an seiner Plattform und den sie umgebenden Produkten gearbeitet. Das Ergebnis war ein Ökosystem, gegen dass der Neuling aus Mountain View zum damaligen Zeitpunkt im direkten Vergleich keine Chance hatte. Seitdem ist viel passiert. Android hat sich zum Liebling von Verbrauchern, Entwicklern und Herstellern gemausert. Die Flut an neuen Modellen nimmt kein Ende. Und Apple und Google liefern sich ein Wettrennen um die besten Innovationen. Den Nutzern von mobilen Geräten kann diese Situation nur recht sein, und letztlich profitieren beide Lager von diesem Wettstreit. Die Frage, warum Android mittlerweile so populär ist, lässt sich schnell beantworten: Google hat von Anfang an auf Offenheit gesetzt. Jeder war und ist eingeladen, mitzumachen. Hardware-Hersteller können Produkte entwickeln, ohne hohe Summen an Lizenzkosten zahlen zu müssen. Und interessierten Programmierern steht mit dem Android Software Development Kit und den Android Development Tools ein leistungsfähiges Gespann zur Entwicklung von Apps zur Verfügung. Dank Java als Programmiersprache und Eclipse als Entwicklungsumgebung fällt der Einstieg im Vergleich zu manch anderer Plattform leicht. Dennoch gibt es für Einsteiger in diese faszinierende Welt vieles zu beachten. Android bietet schier unendliche Möglichkeiten. Und mit jeder Plattform-Version kommen neue Funktionen hinzu. Um diese sicher nutzen zu können, müssen Sie als Entwickler mit einer Reihe von Mechanismen und Konzepten vertraut sein. Dieses Wissen möchte ich Ihnen mit dem vorliegenden Buch gerne vermitteln. Aber nicht in Form einer theoretischen Abhandlung. In vielen kleinen, in sich geschlossenen praxisnahen Beispielen lernen Sie die souveräne Nutzung der Android-Programmierschnittstellen kennen. Natürlich finden Sie alle Programme als Eclipse-Projekte auch auf der Begleit-DVD.

13

Vorwort

Aufbau des Buchs Das Buch ist in fünf Teile gegliedert. In Teil 1, »Grundlagen«, stelle ich Ihnen Android und seine Entwicklerwerkzeuge vor und begleite Sie Schritt für Schritt zu Ihrer ersten App. Außerdem lernen Sie den Android Market als moderne digitale Vertriebsplattform kennen. Der zweite Teil, »Elementare Anwendungsbausteine«, beschäftigt sich mit Komponenten, die in nahezu jeder App vorhanden sind. Hierzu gehört natürlich die Benutzeroberfläche. Aber auch Multitasking und wie es in Android umgesetzt wird, beschreibe ich in diesem Teil ausführlich. In »Telefonfunktionen nutzen« erstellen Sie unter anderem eigene Widgets und Wallpaper und lernen die Sensoren eines Android-Geräts kennen. »Dateien und Datenbanken« befasst sich nicht nur mit der Speicherung und Abfrage von Daten, ich zeige Ihnen außerdem, wie Sie Ihre Apps fit für die Installation auf Wechselmedien machen. Im fünften Teil »Organizer und Multimedia« schließlich nutzen Sie das Mikrofon eines Android-Geräts, um Geräusche aufzunehmen. Sie schießen Fotos mit der eingebauten Kamera und legen Kontakte und Termine an. Jedes Kapitel ist in sich abgeschlossen und beschäftigt sich mit genau einem Themenkomplex. Wenn Sie schon etwas Erfahrung mit Android haben, müssen Sie das Buch also nicht von Deckel zu Deckel durcharbeiten, sondern können sich gezielt einen Aspekt herausgreifen, der Sie besonders interessiert. Neulingen möchte ich die beiden ersten Kapitel als Einstieg ans Herz legen. Sie lernen die Bestandteile von Googles offener Plattform für mobile Geräte kennen, installieren alle benötigten Komponenten und schreiben dann Ihre erste App. Programmierkenntnisse Um die Beispiele nachvollziehen zu können, müssen Sie kein Java-Profi sein, allerdings sollten Sie diese Programmiersprache und ihre Klassenbibliothek zumindest in Grundzügen beherrschen. In Anhang A finden Sie eine Literaturliste mit empfehlenswerten Büchern für den Einstieg in Java. Außerdem finden Sie das Kompendium Java ist auch eine Insel von Christian Ullenboom auf der Begleit-DVD. Unterstützte Android-Versionen Alle Beispiele sind ab Android 2.3 lauffähig. Ausnahmen bilden nur Apps, die spezielle Funktionen von Android 3.0 demonstrieren. Sie können die Programme also für Smartphones und Tablets gleichermaßen nutzen. Danksagung Dieses Buch wäre ohne die Unterstützung von vielen Menschen nicht möglich gewesen. Ihnen allen gebührt mein tief empfundener Dank. Dazu gehören die

14

Vorwort

Mitarbeiterinnen und Mitarbeiter des Verlags Galileo Press, insbesondere meine Lektorin Christine Siedle. Der Weg von der Idee über das Manuskript bis zum fertigen Buch ist lang und manchmal steiniger als erwartet. Für stets offene Ohren, freundliche wie professionelle Unterstützung und manchmal auch Geduld bedanke ich mich herzlich. Mit bewundernswerter Akribie haben Yvonne Wolf, Thomas Bednarek, Mathias Hengl und Dave Richardson jedes einzelne Kapitel gelesen und korrigiert und somit geholfen, die eine oder andere Ungereimtheit zu klären sowie manche Kante zu glätten. Hierfür und zahlreiche wertvolle Tipps vielen Dank. Ebenfalls danke ich Sascha Bluhme, Richard Grötsch und Walter Grötsch für interessante Gespräche, Anregungen und Vorschläge. Meinen Eltern Rudolf und Gertraud Künneth und meinem Bruder Andreas Künneth danke ich für alles, was sie mir auf den Weg gegeben haben. Ohne sie wäre vieles nicht möglich. Der allergrößte Dank aber gebührt meiner Ehefrau Moni für das unermessliche Glück, das sie mir jeden Tag schenkt, für ihre Liebe, ihre Unterstützung und Geduld. Ihr widme ich dieses Buch.

15

Die erste eigene App ist schneller fertig, als Sie vielleicht glauben. Dieses Kapitel führt Sie in leicht nachvollziehbaren Schritten zum Ziel.

2

Hallo Android!

Seit vielen Jahrzenten ist es schöne Tradition, anhand des Beispiels »Hello world!« in eine neue Programmiersprache oder Technologie einzuführen. Dahinter steht die Idee, erste Konzepte und Vorgehensweisen in einem kleinen, überschaubaren Rahmen zu demonstrieren. Android bleibt dieser Tradition treu. Wenn Sie mit dem Eclipse-Projektassistenten ein neues Projekt anlegen, erzeugen die Android Development Tools eine minimale, aber lauffähige Anwendung. Sie gibt einen Text aus, der mit den Worten »Hello World« beginnt. Im Verlauf dieses Kapitels erweitern Sie diese Anwendung um die Möglichkeit, einen Nutzer namentlich zu begrüßen. Ein Klick auf Fertig schließt die App.

2.1

Android-Projekte

Projekte fassen alle Artefakte einer Android-Anwendung zusammen. Dazu gehören unter anderem Quelltexte, Konfigurationsdateien, Testfälle, aber auch Grafiken, Sounds und Animationen. Natürlich sind Projekte keine Erfindung der Android Development Tools (ADT), sondern bilden eines der Kernkonzepte von Eclipse. Sie werden im Arbeitsbereich (engl. workspace) abgelegt. Grundsätzlich können Sie mit beliebig vielen Projekten gleichzeitig arbeiten. Für das Öffnen und Schließen von Projekten ist der Package Manager zuständig.

2.1.1

Projekte anlegen

Um ein neues Projekt anzulegen, wählen Sie in Eclipse File 폷 New 폷 Project. Klicken Sie nun auf Android 폷 Android Project, und wechseln Sie mit Next auf die zweite Seite des Assistenten. Vergeben Sie dort zunächst einen Projektnamen 1, ich habe zum Beispiel Hallo Android gewählt, und übernehmen Sie die weiteren Einstellungen aus Abbildung 2.1. Unter Contents müssen Sie Create new project

35

2

Hallo Android!

in workspace 2 markieren. Stellen Sie das Build Target auf Android 2.2 5, und tragen Sie bei Min SDK Version 6 »8« ein.

1 2 3 4

5

6

Abbildung 2.1

Anlegen des Projekts »Hallo Android«

Der neben Location 4 angezeigte Pfad verweist auf das Projektwurzelverzeichnis. Sofern Sie das Häkchen vor Use default location 3 nicht entfernt haben (was Sie auch nicht tun sollten), ist dies ein Unterverzeichnis des Eclipse-Arbeitsbereichs. Dieser liegt standardmäßig im Ordner workspace unterhalb Ihres

36

Android-Projekte

Heimatverzeichnisses. Da ich mehrere solcher Workspaces parallel nutze, habe ich mit File 폷 Switch Workspace 폷 Other den Pfad C:\Users\Thomas\Entwicklung\Android eingestellt. Der Application name in der Rubrik Properties wird später auf dem Gerät bzw. im Emulator angezeigt. Bei der Vergabe des Package name sollten Sie besonders sorgfältig vorgehen, vor allem wenn Sie eine Anwendung im Android Market veröffentlichen möchten. Denn der hier eingetragene Paketname referenziert genau eine App, muss also eindeutig sein. Idealerweise folgen Sie den Namenskonventionen für Java-Pakete und tragen (in umgekehrter Reihenfolge) den Namen einer Ihnen gehörenden Internet-Domain gefolgt von einem Punkt und dem Namen der App ein. Verwenden Sie nur Kleinbuchstaben, und vermeiden Sie Sonderzeichen, insbesondere das Leerzeichen. Wie Sie gleich sehen werden, gehören Activities zu den Grundbausteinen einer Android-Anwendung. Sofern das Häkchen vor Create Activity gesetzt ist (falls nicht, holen Sie es nach), wird der Assistent automatisch eine Activity mit dem von Ihnen eingegebenen Namen erzeugen. Mit Finish schließen Sie den Projektassistenten. Nachdem Eclipse alle Dateien und Verzeichnisse angelegt hat, wird das Projekt automatisch im Package Explorer angezeigt. Denken Sie daran, dass Sie auf alle Eclipse-Sichten über das Menü Window 폷 Show View zugreifen können.

2.1.2

Projektstruktur

Android-Apps bestehen aus einer ganzen Reihe von Artefakten, die zu einer baumartigen Struktur zusammengefasst werden. Klicken Sie die Wurzel dieses Baums (also den Projektnamen) oder eines seiner Unterelemente mit der rechten Maustaste an, öffnet sich ein Kontextmenü. Welche Funktionen hierbei angeboten werden, hängt vom angeklickten Objekt ab. Wie Sie bereits aus dem ersten Kapitel wissen, starten Sie auf diese Weise (Run As 폷 Android Application) die Anwendung im Emulator oder einem angeschlossenen Gerät. Wenn Sie möchten, können Sie dies nun ausprobieren. Ein Projekt enthält die in Abbildung 2.2 gezeigten Knoten src, gen, Android 2.2, assets und res. Ferner sind die Dateien AndroidManifest.xml und default.properties zu sehen. Letztere wird von den Android Development Tools (ADT) verwendet und sollte von Ihnen nicht verändert werden. In ihr wird unter anderem vermerkt, gegen welche Plattform-Version eine Anwendung entwickelt wird. Auch der Knoten Android 2.2 hat für Sie als Entwickler keine Bedeutung. Allerdings offenbart er die Pakete und Klassen, aus denen die Android-Klassenbibliothek besteht. Wenn Sie neugierig sind, können Sie einen Blick in seine weit verzweigte Struktur werfen.

37

2.1

2

Hallo Android!

Abbildung 2.2

Das Projekt »Hallo Android« im Package Explorer

Sowohl default.properties als auch Android 2.2 korrespondieren übrigens mit dem Build Target des Projektassistenten. Hätten Sie beim Anlegen des Projekts eine andere Android-Version gewählt, hätte auch der Knoten einen anderen Namen, beispielsweise Android 1.6. Wenn Sie bei der Installation des Android SDK mehr als eine Plattform heruntergeladen haben, können Sie dies auch nachträglich ausprobieren. Klicken Sie hierzu im Package Explorer mit der rechten Maustaste auf den Projektnamen, und wählen Sie anschließend Properties. Klicken Sie nun auf Android, und wählen Sie unter Project Build Target eine andere Android-Version aus. Da die ausgewählte Android-Version große Auswirkungen auf die zur Verfügung stehenden Klassen und Methoden hat, sollten Sie einen solchen Wechsel gut abwägen. Vor allem der Schritt von einer höheren zu einer niedrigeren Version kann zu Problemen führen, wenn beispielsweise auf Klassen Bezug genommen wird, die es in der früheren Version noch nicht gab. Das Projekt kann in diesem Fall nicht gebaut werden. Bevor Sie fortfahren, stellen Sie als Build Target bitte wieder Android 2.2 ein. Quelltexte werden in src abgelegt. Der Package Explorer zeigt aktuell nur die Klasse HalloAndroidActivity, die sich im Paket com.thomaskuenneth.hallo

38

Android-Projekte

befindet. Beides hatten Sie im Projektassistenten eingetragen. Übrigens können Sie bequem neue Klassen anlegen, indem Sie das Paket mit der rechten Maustaste anklicken und New 폷 Class anklicken. Auch gen enthält ein Paket com.thomaskuenneth.hallo. Es beinhaltet die Klasse R. Wie Sie bald sehen werden, hat sie große Bedeutung beim Zugriff auf unter-

schiedlichste Elemente einer Android-App. Allerdings wird R durch die ADT verwaltet und darf deshalb von Ihnen nicht verändert werden. Ihr Inhalt ergibt sich aus Dateien des Verzeichnisses res. Dessen Unterordner values enthält beispielsweise die Datei strings.xml. Sie nimmt Texte auf, die später im Quelltext mithilfe der Klasse R referenziert werden. Wann immer Sie Änderungen an dieser Datei vornehmen, sorgen die Android Development Tools (ADT) automatisch dafür, dass R entsprechend angepasst und übersetzt wird. Das Verzeichnis assets bleibt in vielen Projekten leer. Es nimmt nämlich Dateien auf, die zwar Bestandteil einer Anwendung sind, aber nicht durch Standardmechanismen von Android geladen werden können. AndroidManifest.xml ist die zentrale Beschreibungsdatei einer Anwendung. In ihr werden unter anderem die Bestandteile des Programms aufgeführt. Wie Sie später noch sehen werden, sind dies sogenannte Activities, Services, Broadcast Receiver und Content Provider. Die Datei enthält aber auch Informationen darüber, welche Rechte eine App benötigt, welche Hardware sie erwartet und unter welchen Systemversionen sie lauffähig ist. 3Um AndroidManifest.xml zu bearbeiten, stellen die ADT einen eigenen Editor zur Verfügung. Auf der in Abbildung 2.3 gezeigten Registerkarte Application werden Einstellungen vorgenommen, die sich auf die gesamte App beziehen. Debuggable beispielsweise steuert, ob eine Anwendung auf einem realen Gerät mit einem Debugger untersucht werden kann. Hinter der Registerkarte AndroidManifest.xml verbirgt sich ein klassischer XML-Texteditor. Sie können die Datei also mittels Klapplisten, Text- und Ankreuzfeldern bearbeiten oder durch das Eingeben und Bearbeiten von XML-Tags und Attributen. Öffnen Sie AndroidManifest.xml, und wechseln Sie in die XML-Ansicht, um sich einen ersten Eindruck von ihrer Struktur zu verschaffen. Es gibt ein Wurzelelement mit den beiden Kindern und . Android-Apps bestehen (neben den weiter oben bereits kurz genannten anderen Bausteinen) aus mindestens einer Activity. Hierbei handelt es sich, stark vereinfacht ausgedrückt, um Bildschirmseiten. Verschiedene Aspekte einer Anwendung wie Listen, Übersichten, Such- und Eingabemasken werden als eigene Activities realisiert und als Unterelemente von in AndroidManifest.xml eingetragen.

39

2.1

2

Hallo Android!

Abbildung 2.3

Editor für die Datei AndroidManifest.xml

Das Attribut android:minSdkVersion gibt an, welche Android-Version auf einem Gerät mindestens vorhanden sein muss, um die App nutzen zu können. Ist diese Voraussetzung nicht erfüllt, wird die Installation abgebrochen. Android Market zeigt das Programm in so einem Fall allerdings gar nicht an. Bislang haben Sie nur mit einem virtuellen Android-Gerät (AVD) gearbeitet. Im folgenden Abschnitt zeige ich Ihnen, wie Sie mithilfe der sogenannten Run Configurations von Eclipse auch bei mehreren Emulatoren den Überblick behalten.

2.1.3

Run Configurations

Möchten Sie eine Anwendung nicht ausschließlich für den Eigengebrauch entwickeln, sollten Sie sie unter verschiedenen Android-Versionen und Gerätetypen testen. Falls Sie planen, Ihre App im Android Market zu veröffentlichen, wird dies sogar noch viel wichtiger. Mit dem Ihnen bereits bekannten SDK Manager ist ein virtuelles Android-Gerät (AVD) mit wenigen Mausklicks angelegt. Wählen Sie hierzu Window 폷 Android SDK and AVD Manager, und klicken Sie anschließend auf Virtual Devices. Mit New öffnen Sie den Dialog Create new Android Virtual Device (AVD).

40

Android-Projekte

Übernehmen Sie die Einstellungen aus Abbildung 2.4. Sie erzeugen damit ein virtuelles Gerät im Querformat, das unter Android 1.5 läuft. Falls in der Klappliste Target kein entsprechender Eintrag vorhanden ist, müssen Sie die korrespondierende Plattform erst herunterladen. Schließen Sie in diesem Fall den Dialog mit Cancel, und wechseln Sie anschließend auf die Seite Available Packages, auf der Sie ein entsprechendes Paket finden. Bereits installierte Plattformen erscheinen übrigens unter Installed Packages. Um das Projekt Hallo Android in dem neu angelegten AVD auszuführen, klicken Sie den Projektnamen im Package Explorer mit der rechten Maustaste an und wählen Run As 폷 Run Configurations.

Abbildung 2.4

Dialog zum Anlegen eines AVDs

Da die App schon im Emulator ausgeführt wurde, hat Eclipse automatisch eine Run Configuration erzeugt. Sie ist in Abbildung 2.5 zu sehen. Auf der Registerkarte Target können Sie einstellen, ob die IDE selbstständig ein (virtuelles) Gerät auswählen oder während des Startvorgangs nachfragen soll. Klicken Sie auf Manual. Mit Apply übernehmen Sie Ihre Änderung. Schließen Sie den Dialog mit Close.

41

2.1

2

Hallo Android!

Abbildung 2.5

Der Dialog »Run Configurations«

Ist Ihnen aufgefallen, dass das von Ihnen angelegte Gerät mit Android 1.5 nicht unter Select a preferred Android Virtual Device for deployment erscheint? Der Grund ist, dass derzeit Android 2.2 als Project Build Target auf der Seite Android der Projekteigenschaften eingetragen ist. Eclipse erkennt also, dass die Versionsnummer des AVDs zu niedrig ist. Bitte lassen Sie diese Einstellung zunächst bestehen. Versuchen Sie nun, Hallo Android mit Run 폷 Run zu starten. Eclipse öffnet den in Abbildung 2.6 gezeigten Android Device Chooser. Klicken Sie auf Launch a new Android Virtual Device, und wählen Sie Cupcake_QVGA-L, also das gerade angelegte virtuelle Gerät.

42

Die Benutzeroberfläche

Abbildung 2.6

Der Dialog »Android Device Chooser«

Ein Klick auf OK startet den Emulator. Anschließend wird versucht, die App zu installieren. Dies schlägt fehl. Der Grund ist natürlich die zu niedrige Versionsnummer des AVDs. Eine entsprechende Fehlermeldung ist in der Sicht Console zu sehen. Das Problem lässt sich allerdings sehr leicht beheben. Ändern Sie hierzu einfach in der Datei AndroidManifest.xml unter android:minSdkVersion die Zahl 8 in eine 3 um. Führen Sie anschließend Run 폷 Run erneut aus. Da bereits eine Emulator-Instanz läuft, können Sie im Android Device Chooser auf Choose a running Android Device klicken. Im nächsten Abschnitt werden Sie erste Erweiterungen an Hallo Android vornehmen. Zunächst werde ich Ihnen zeigen, wie in Android Texte gespeichert werden und wie man in einer App auf diese zugreift.

2.2

Die Benutzeroberfläche

Die Benutzeroberfläche ist das Aushängeschild einer Anwendung. Gerade auf mobilen Geräten mit vergleichsweise kleinen Bildschirmen sollte jede Funktion leicht zugänglich und intuitiv erfassbar sein. Android unterstützt Sie bei der Gestaltung durch eine große Auswahl an Bedienelementen.

43

2.2

2

Hallo Android!

2.2.1

Texte

Bilder und Symbole sind ein wichtiges Gestaltungsmittel. Sinnvoll eingesetzt, helfen sie dem Anwender nicht nur beim Bedienen des Programms, sondern sorgen zudem für ein angenehmes, schönes Äußeres. Dennoch spielen auch Texte eine sehr wichtige Rolle. Sie werden in den unterschiedlichsten Bereichen einer Anwendung eingesetzt: 왘

als Beschriftungen von Bedienelementen



für erläuternde Texte, die durch einen Screenreader vorgelesen werden (im Android Market stehen entsprechende Programme zum Download bereit)



für Hinweis- und Statusmeldungen

Die fertige Version von Hallo Android soll den Benutzer zunächst begrüßen und ihn nach seinem Name fragen. Im Anschluss wird ein persönlicher Gruß angezeigt. Nach dem Anklicken einer Schaltfläche beendet sich die App. Aus dieser Beschreibung ergeben sich die folgenden Texte. Die Bezeichner vor dem jeweiligen Text werden Sie später im Programm wiederfinden: 왘

willkommen – Guten Tag. Schön, dass Sie mich gestartet haben. Bitte verraten

Sie mir Ihren Namen. 왘

weiter – Weiter



hallo – Hallo . Ich freue mich, Sie kennenzulernen.



fertig – Fertig

Ein Großteil der Texte wird zur Laufzeit so ausgegeben, wie sie schon während der Programmierung erfasst wurden. Eine kleine Ausnahme bildet die Grußformel. Sie besteht aus einem konstanten und einem variablen Teil. Letzterer ergibt sich erst, nachdem der Anwender seinen Namen eingetippt hat. Wie Sie gleich sehen werden, ist es in Android sehr einfach, dies zu realisieren. Da Sie Apps in der Programmiersprache Java schreiben, könnten Sie die auszugebenden Meldungen einfach im Quelltext ablegen. Das sähe folgendermaßen aus (ich habe die String-Konstante aus Gründen der besseren Lesbarkeit in drei Teile zerlegt): nachricht .setText("Guten Tag. Schön, dass " + "Sie mich gestartet haben." + " Bitte verraten Sie mir Ihren Namen.");

Das hätte allerdings eine ganze Reihe von Nachteilen. Da jede Klasse in einer eigenen Datei abgelegt wird, merkt man oft nicht, wenn man gleiche Texte mehr-

44

Die Benutzeroberfläche

fach definiert. Dies vergrößert die Installationsdatei der App und kostet unnötig Speicher. Außerdem wird es auf diese Weise sehr schwer, mehrsprachige Anwendungen zu bauen. Wenn Sie eine App über den Android Market vertreiben möchten, sollten Sie neben den deutschsprachigen Texten aber mindestens eine englische Lokalisierung ausliefern. Unter Android werden Texte daher zentral in der Datei strings.xml abgelegt. Sie befindet sich im Verzeichnis values. Ändern Sie die durch den Projektassistenten angelegte Fassung folgendermaßen ab: Hallo Android! Guten Tag. Schön, dass Sie mich gestartet haben. Bitte verraten Sie mir Ihren Namen. Hallo %1$s. Ich freue mich, Sie kennenzulernen. Weiter Fertig Listing 2.1

strings.xml

Das Attribut name des Elements wird später im Quelltext als Bezeichner verwendet. Der Name muss also projektweit eindeutig sein. Ist Ihnen im Listing die fett gesetzte Zeichenfolge %1$s aufgefallen? Android wird an dieser Stelle den vom Benutzer eingegebenen Namen einfügen. Wie dies funktioniert, zeige ich Ihnen später. Nach dem Speichern Ihrer Änderungen sollten Sie zunächst aber noch einen Blick auf die Klasse R unter gen werfen. Sie enthält zahlreiche als public static final gekennzeichnete Klassen, unter anderem string. Diese wiederum besteht

45

2.2

2

Hallo Android!

aus einer Reihe von Konstanten des Typs int. Ihre Namen entsprechen den nameAttributen aus strings.xml. Die Android Development Tools (ADT) aktualisieren R nach Änderungen an Dateien unterhalb des Verzeichnisses res automatisch. Wenn Sie also Texte oder Zeichenketten in Ihrer App benötigen, tragen Sie diese -Elemente in strings.xml ein und greifen im Quelltext via R.string auf den jeweiligen Namen zu. Vielleicht fragen Sie sich, wie Sie Ihr Programm mehrsprachig ausliefern können, wenn es genau eine zentrale strings.xml gibt. Neben dem Verzeichnis values kann es lokalisierte Ausprägungen geben, die auf das Minuszeichen und ein aus zwei Buchstaben bestehendes Sprachkürzel enden (zum Beispiel values-en oder values-fr). Die Datei string.xml in diesen Ordnern enthält Texte in den korrespondierenden Sprachen, also Englisch oder Französisch. Muss Android auf eine Zeichenkette zugreifen, geht das System vom Speziellen zum Allgemeinen. Ist die Standardsprache also beispielsweise Englisch, wird zuerst versucht, den Text in values-en/ strings.xml zu finden. Gelingt dies nicht, findet values/strings.xml Verwendung.

Abbildung 2.7

46

Die Registerkarte »Resources« des strings.xml-Editors

Die Benutzeroberfläche

In dieser Datei müssen also alle Strings definiert werden. Lokalisierungen hingegen können unvollständig sein. Ausführliche Hinweise zur Internationalisierung und der Verwendung von Ressourcen finden Sie in der Entwicklerdokumentation unter Localization.1 Wie AndroidManifest.xml kann auch strings.xml mittels Listen und Schaltflächen bearbeitet werden. Die hierfür zuständige Registerkarte Resources des Editors ist in Abbildung 2.7 zu sehen. Neben Add und Remove zum Anlegen bzw. Löschen von Elementen gibt es die Schaltflächen Up und Down. Sie verschieben den markierten Eintrag in Richtung Dateianfang bzw. -ende. Im folgenden Abschnitt stelle ich Ihnen sogenannte Views vor. Hierbei handelt es sich um die Grundbausteine, aus denen die Benutzeroberfläche einer App zusammengesetzt wird.

2.2.2

Views

Hallo Welt besteht auch nach vollständiger Realisierung aus sehr wenigen Bedienelementen: 왘

einem nicht editierbaren Textfeld, das den Gruß unmittelbar nach dem Programmstart sowie nach Eingabe des Namens darstellt



einer Schaltfläche, die je nach Situation mit Weiter oder Fertig beschriftet ist



einem Eingabefeld, das nach dem Anklicken der Schaltfläche Weiter ausgeblendet wird

Abbildung 2.8

Prototyp der Benutzeroberfläche von »Hallo Android«

Wie die Komponenten auf dem Bildschirm platziert werden sollen, zeigt ein sogenannter Wireframe, den Sie in Abbildung 2.8 sehen. Man verwendet solche abstrakten Darstellungen gerne, um die logische Struktur einer Bedienoberfläche in das Zentrum des Interesses zu rücken.

1 http://developer.android.com/guide/topics/resources/localization.html

47

2.2

2

Hallo Android!

Unter Android leiten alle Bedienelemente direkt oder indirekt von der Klasse android.view.View ab. Jede View belegt einen rechteckigen Bereich des Bildschirms. Ihre Position und Größe wird durch Layouts bestimmt. Diese wiederum erben von android.view.ViewGroup, ebenfalls ein Kind von View. Sie haben keine eigene grafische Repräsentation, sondern sind Container für weitere Views und ViewGroups. Die Text- und Eingabefelder sowie Schaltflächen, die in Hallo Android verwendet werden, sind also Views. Konkret verwenden wir die Klassen Button, TextView und EditText. Wo sie auf dem Bildschirm positioniert werden und wie groß sie sind, wird hingegen durch die ViewGroup LinearLayout festgelegt. Zur Laufzeit einer Anwendung manifestiert sich ihre Benutzeroberfläche demnach als Objektbaum. Aber nach welcher Regel wird er erzeugt? Wie definieren Sie als Entwickler den Zusammenhang zwischen einem Layout, einem Textfeld und einer Schaltfläche? Java-Programmierer sind gewohnt, die Oberfläche programmatisch zusammenzusetzen. Nicht nur im Swing-Umfeld finden sich unzählige Ausdrücke im Stil von JPanel p = new JPanel(); JButton b = new JButton(); p.add(b);. Auch unter Android könnten Sie die Bedienelemente auf diese Weise zusammenfügen: ScrollView v = new ScrollView(context); LinearLayout layout = new LinearLayout(context); layout.setOrientation(LinearLayout.VERTICAL); v.addView(layout); layout.addView(getCheckbox(context, Locale.GERMANY)); layout.addView(getCheckbox(context, Locale.US)); layout.addView(getCheckbox(context, Locale.FRANCE)); Listing 2.2

Beispiel für den programmatischen Bau einer Oberfläche

Allerdings ist dies nicht die typische Vorgehensweise – diese lernen Sie im folgenden Abschnitt kennen.

2.2.3

Oberflächenbeschreibungen

Eine Android-Anwendung beschreibt ihre Benutzeroberflächen normalerweise mittels XML-basierter Layoutdateien. Diese werden zur Laufzeit der App zu Objektbäumen »aufgeblasen«. Alle Bedienelemente von Hallo Android werden in einen Container des Typs LinearLayout gepackt. Seine Kinder erscheinen entweder neben- oder untereinander auf dem Bildschirm. Wie Sie gleich sehen wer-

48

Die Benutzeroberfläche

den, steuert das Attribut android:orientation die Laufrichtung. Auch die Größe der Views und ViewGroups wird so definiert. Hierfür gibt es android:layout_ width und android:layout_height. Oberflächenbeschreibungen werden in layout, einem Unterverzeichnis von res, gespeichert. Beim Anlegen des Projekts hat Eclipse dort die Datei main.xml abgelegt. Öffnen Sie diese, und ändern Sie sie folgendermaßen ab: Listing 2.3

main.xml

Die XML-Datei bildet die Hierarchie der Benutzeroberfläche ab. Demzufolge ist das Wurzelelement. Mein Beispiel enthält die drei Kinder , und . Jedes Element hat die bereits kurz angesprochenen Attribute android:layout_width und android:layout_height.

49

2.2

2

Hallo Android!

Deren Wert fill_parent besagt, dass die Komponente die Breite oder Höhe des Elternobjekts erben soll. wrap_content hingegen bedeutet, dass sich die Größe aus dem Inhalt der View ergibt, beispielsweise der Beschriftung einer Schaltfläche. Die Zeile android:layout_gravity="right" sorgt dafür, dass die Schaltfläche rechtsbündig angeordnet wird. Ist Ihnen aufgefallen, dass keinem Bedienelement ein Text oder eine Beschriftung zugewiesen wird? Und was bedeuten Zeilen, die mit android:id="@+id/ beginnen? Wie Sie bereits wissen, erzeugt Android zur Laufzeit einer Anwendung aus den Oberflächenbeschreibungen entsprechende Objektbäume. Zu der in der XML-Datei spezifizierten Schaltfläche gibt es also eine Instanz der Klasse Button. Um eine Referenz auf diese ermitteln zu können, wird ein Name definiert, beispielsweise weiter_fertig. Wie schon bei strings.xml sorgen die Android Development Tools (ADT) dafür, dass nach Änderungen an Layoutdateien korrespondierende Einträge in der Klasse R vorgenommen werden. Wenn Sie sich diese nach dem Speichern von main.xml ansehen, entdecken Sie die Klasse id mit den drei Konstanten eingabe, nachricht und weiter_fertig. Die Angabe android:id="@+id/ sorgt also dafür, dass einer View ein Bezeichner zugewiesen wird, auf den mittels R.id zugegriffen werden kann. Wozu Sie das benötigen, zeige ich Ihnen im folgenden Abschnitt.

2.3

Programmlogik und -ablauf

Viele Desktop-Anwendungen sind datei- oder dokumentenzentriert. Egal ob Textverarbeitung, Tabellenkalkulation oder Layoutprogramm – ihr Aufbau ist stets gleich. Den überwiegenden Teil des Bildschirms oder Fensters belegt ein Arbeitsbereich, der ein Dokument (oder einen Teil davon) darstellt. Um ihn gruppieren sich Symbolleisten und Paletten, mit denen Elemente des Dokuments bearbeitet bzw. verändert werden. Das gleichzeitige Darstellen von Werkzeugen und Inhalt ist auf den kleinen Bildschirmen mobiler Geräte aber nicht sinnvoll. Der Benutzer würde kaum etwas erkennen. Als Entwickler müssen Sie Ihre Anwendung deshalb in Funktionsblöcke oder Bereiche unterteilen, die genau einen Aspekt Ihres Programms abbilden. Ein anderes Beispiel: E-Mail-Clients zeigen die wichtigsten Informationen zu eingegangenen Nachrichten häufig in einer Liste an. Neben oder unter der Liste befindet sich ein Lesebereich, der das aktuell ausgewählte Element vollständig anzeigt. Auch dies lässt sich aufgrund des geringen Platzes auf Smartphones nicht

50

Programmlogik und -ablauf

sinnvoll realisieren. Stattdessen zeigen entsprechende Anwendungen dem Nutzer zunächst eine Übersicht (die Liste der eingegangenen Nachrichten) und verzweigen in eine Detailansicht, sobald eine Zeile der Liste angeklickt wird.

2.3.1

Activities

Unter Android ist das Zerlegen einer App in solche (aufgabenorientierten) Teile bzw. Funktionsblöcke ein grundlegendes Architekturmuster. Die gerade eben skizzierten Aufgaben bzw. »Aktivitäten« – E-Mail auswählen und E-Mail anzeigen – werden zu Bausteinen, die die Plattform Activities nennt. Eine Anwendung besteht aus mindestens einer solchen Activity. Je nach Funktionsumfang können es aber auch viel mehr sein. Normalerweise ist jeder Activity eine Benutzeroberfläche, also ein Baum bestehend aus Views und ViewGroups, zugeordnet. Activities bilden demnach die vom Anwender wahrgenommenen Bausteine einer App. Sie können sich gegenseitig aufrufen. Die Vorwärtsnavigation innerhalb einer Anwendung wird z. B. auf diese Weise realisiert. Da das System Activities auf einem Stapel ablegt, müssen Sie sich als Entwickler nicht darum kümmern, von wem Ihre Activity aufgerufen wird. Drückt der Benutzer den Zurück-Knopf, wird automatisch die zuvor angezeigte Activity reaktiviert. Vielleicht fragen Sie sich, aus wie vielen Activities Hallo Android besteht. Theoretisch könnten Sie die App in drei Activities unterteilen, die Sie unabhängig voneinander anlegen müssten: 1. Begrüßung anzeigen 2. Namen eingeben 3. Personalisierten Gruß anzeigen Das wäre sinnvoll, wenn die entsprechenden Aufgaben umfangreiche Benutzereingaben oder aufwendige Netzwerkkommunikation erfordern. Dies ist nicht der Fall. Da die gesamte Anwendung aus sehr wenigen Bedienelementen besteht, ist es in diesem Fall zielführender, alle Funktionen in einer Activity abzubilden. Übernehmen Sie die im Folgenden dargestellte erste Version der Klasse HalloAndroidActivity. Um die Anwendung zu starten, wählen Sie Run 폷 Run. Nach der Installation sollte das Emulatorfenster in etwa Abbildung 2.9 entsprechen.

51

2.3

2

Hallo Android!

Abbildung 2.9

Erste eigene Version von »Hallo Android«

Das Textfeld nimmt Eingaben entgegen. Das Anklicken der Schaltfläche Weiter löst aber selbstverständlich noch keine Aktion aus. Diese werden wir im nächsten Abschnitt implementieren. Zuvor möchte ich Sie aber mit einigen Schlüsselstellen des Quelltexts vertraut machen. Ganz wichtig: Jede Activity erbt von android.app.Activity oder von spezialisierten Kindklassen. Beispielsweise kennt die Plattform ListActivity2, die das Erstellen von Auswahl- und Übersichtslisten stark vereinfacht. 2 http://developer.android.com/reference/android/app/ListActivity.html

52

Programmlogik und -ablauf

package com.thomaskuenneth.hallo; import import import import

android.app.Activity; android.os.Bundle; android.widget.Button; android.widget.TextView;

public class HalloAndroidActivity extends Activity { private TextView nachricht; private Button weiter_fertig; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); nachricht = (TextView) findViewById(R.id.nachricht); weiter_fertig = (Button) findViewById(R.id.weiter_fertig); nachricht.setText(R.string.willkommen); weiter_fertig.setText(R.string.weiter); } } Listing 2.4

Erste Version von HalloAndroidActivity.java

Haben Sie bemerkt, dass die gesamte Programmlogik innerhalb der Methode onCreate() liegt? Activities haben einen ausgeklügelten Lebenszyklus, den ich Ihnen in in Kapitel 4, »Activities und Broadcast Receiver«, ausführlicher vorstelle. Seine einzelnen Stationen werden durch bestimmte Methoden der Klasse Activity realisiert, die Sie bei Bedarf überschreiben können. Beispielsweise informiert die Plattform eine Activity, kurz bevor sie beendet, unterbrochen oder zerstört wird. Die Methode onCreate() wird immer überschrieben. Sie ist der ideale Ort, um die Benutzeroberfläche aufzubauen und um Variablen zu initialisieren. Das Laden und Anzeigen der Bedienelemente reduziert sich auf eine Zeile Quelltext: setContentView(R.layout.main);. Sie sorgt dafür, dass alle Views und ViewGroups, die in der Datei main.xml definiert wurden, zu einem Objektbaum entfaltet werden und dieser als Inhaltsbereich der Activity gesetzt wird. Warum ich den Begriff »entfalten« verwende, erkläre ich Ihnen in Kapitel 5, »Benutzeroberflächen«.

53

2.3

2

Hallo Android!

Der Inhalt des Textfeldes nachricht und die Beschriftung der Schaltfläche weiter_fertig wird auf dieselbe Weise festgelegt. Zunächst ermitteln wir durch Aufruf der Methode findViewById() eine Referenz auf das gewünschte Objekt. Anschließend wird dessen setText() ein Text übergeben. Er ist in values.xml definiert.

2.3.2

Benutzereingaben

Um Hallo Android zu komplettieren, müssen wir auf das Anklicken der Schaltfläche weiter_fertig reagieren. Beim ersten Mal wird das Textfeld eingabe ausgelesen und als persönlicher Gruß in nachricht eingetragen. Anschließend wird das Textfeld ausgeblendet und die Beschriftung der Schaltfläche geändert. Wird diese ein zweites Mal angeklickt, beendet sich die App. package com.thomaskuenneth.hallo; import import import import import import import

android.app.Activity; android.os.Bundle; android.view.View; android.view.View.OnClickListener; android.widget.Button; android.widget.EditText; android.widget.TextView;

public class HalloAndroidActivity extends Activity { private TextView nachricht; private EditText eingabe; private Button weiter_fertig; private boolean erster_klick; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); nachricht = (TextView) findViewById(R.id.nachricht); eingabe = (EditText) findViewById(R.id.eingabe); weiter_fertig = (Button) findViewById(R.id.weiter_fertig); erster_klick = true; nachricht.setText(R.string.willkommen);

54

Programmlogik und -ablauf

weiter_fertig.setText(R.string.weiter); weiter_fertig.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (erster_klick) { nachricht.setText(getString(R.string.hallo, eingabe.getText())); eingabe.setVisibility(View.INVISIBLE); weiter_fertig.setText(R.string.fertig); erster_klick = false; } else { finish(); } } }); } } Listing 2.5

HalloAndroid.java (zweite Version)

Um auf das Anklicken der Schaltfläche reagieren zu können, wird ein sogenannter OnClickListener registriert. Dieses Interface besteht aus der Methode onClick(). Die hier vorgestellte Implementierung nutzt die boolean-Variable erster_klick, um die durchzuführenden Aktionen zu bestimmen. eingabe. setVisibility(View.INVISIBLE); blendet das Eingabefeld aus. getString(R. string.hallo, eingabe.getText()) liefert den in values.xml definierten persönlichen Gruß und fügt an der Stelle %1$s den durch den Benutzer eingetippten Namen ein. Um die App zu beenden, wird die Methode finish() der Klasse Activity aufgerufen.

2.3.3

Der letzte Schliff

In diesem Abschnitt möchte ich Ihnen zeigen, wie Sie Hallo Android den letzten Schliff geben. Beispielsweise kann das System in leeren Eingabefeldern einen Hinweis anzeigen, was der Benutzer eingeben soll. Hierzu fügen Sie in der Datei strings.xml die folgende Zeile ein: Vorname Nachname

Anschließend erweitern Sie in main.xml das Element um das Attribut android:hint="@string/vorname_nachname". Abbildung 2.10 zeigt das entsprechend abgeänderte Programm.

55

2.3

2

Hallo Android!

Abbildung 2.10

Leeres Eingabefeld mit Hinweis

Drücken Sie während der Eingabe eines Namens auf Enter, wandert der Cursor in die nächste Zeile. Auch die Höhe des Eingabefeldes nimmt zu. Dieses Verhalten lässt sich sehr leicht unterbinden. Erweitern Sie hierzu einfach um android:singleLine="true". Und noch ein Tipp: android:inputType="textCapWords" wandelt den ersten Buchstaben eines Worts automatisch in einen Großbuchstaben um. Fällt Ihnen noch ein Defizit der gegenwärtigen Version auf? Solange der Benutzer keinen Namen eingetippt hat, sollte die Schaltfläche Weiter nicht anwählbar sein. Das lässt sich mithilfe eines sogenannten TextWatchers leicht realisieren. Fügen Sie in der Methode onCreate() vor der Zeile erster_klick = true; folgendes Quelltextfragment ein: eingabe.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) {

56

Programmlogik und -ablauf

weiter_fertig.setEnabled(s.length() > 0); } }); weiter_fertig.setEnabled(false); Listing 2.6

Ausschnitt aus HalloAndroidActivity.java

Jedes Mal, wenn ein Zeichen eingegeben oder gelöscht wird, ruft Android unsere Implementierung der Methode afterTextChanged() auf. Diese ist sehr einfach gehalten: Falls der Name mindestens ein Zeichen lang ist, kann die Schaltfläche Weiter angeklickt werden. Als kleine Übung können Sie versuchen, die Prüfroutine so zu erweitern, dass Vor- und Nachname vorhanden sein müssen. Prüfen Sie der Einfachheit halber, ob der eingegebene Text ein Leerzeichen enthält, das nicht am Anfang und nicht am Ende steht.

57

2.3

Android-Geräte enthalten zahlreiche Sensoren. Diese lassen sich mit geringem Aufwand in eigenen Apps nutzen. Wie das funktioniert, zeige ich Ihnen in diesem Kapitel.

9

Sensoren und GPS

Moderne Mobiltelefone schalten ihre Anzeige ab, sobald man sie in Richtung des Kopfes bewegt. Die Darstellung auf dem Bildschirm passt sich der Ausrichtung des Geräts an. Spiele reagieren auf Bewegungsänderungen. Karten-Apps erkennen automatisch den gegenwärtigen Standort. Und Restaurant- oder Kneipenführer beschreiben nicht nur den kürzesten Weg zur angesagten Döner-Bude, sondern präsentieren die Meinungen anderer Kunden und bieten Alternativen an. Dies und noch viel mehr ist möglich, weil die Android-Plattform eine beeindruckende Sensorenphalanx beinhaltet, die von allen Apps genutzt werden kann.

9.1

Sensoren

Android stellt seine Sensoren über eine Instanz der Klasse SensorManager zur Verfügung. Der Aufruf getSystemService(SENSOR_SERVICE) liefert eine entsprechende Referenz. Die Methode ist in allen von android.content.Context abgeleiteten Klassen vorhanden, beispielsweise in android.app.Activity und android.app.Service.

9.1.1

Die Klasse SensorManager

Nachdem Sie mit getSystemService(SENSOR_SERVICE) eine Referenz auf SensorManager ermittelt haben, können Sie auf verschiedene Weise prüfen, welche Sensoren in Ihrer App zur Verfügung stehen. Vorhandene Sensoren ermitteln Folgendes Quelltextfragment listet alle vorhandenen Sensoren auf: List sensors = manager.getSensorList(Sensor.TYPE_ALL); for (Sensor s : sensors) {

209

9

Sensoren und GPS

Log.d(TAG, s.getName() + " (Hersteller: " + s.getVendor() + " , Version: " + s.getVersion() + ")"); } Listing 9.1

Vorhandene Sensoren ermitteln

Anstelle von TYPE_ALL können Sie die übrigen mit TYPE_ beginnenden Konstanten der Klasse Sensor nutzen, um nach einer bestimmten Art Ausschau zu halten. In so einem Fall ist es meist einfacher, stattdessen getDefaultSensor() aufzurufen. Allerdings weist die Android-Dokumentation darauf hin, dass diese Methode unter Umständen einen Sensor liefert, der gefilterte oder gemittelte Werte produziert. Möchten Sie dies zum Beispiel aus Genauigkeitsgründen nicht, verwenden Sie getSensorList(). Neben ihren Namen und Herstellern liefern Sensoren Informationen zu ihrem Stromverbrauch (getPower()), ihrem Wertebereich (getMaximumRange()) und ihrer Genauigkeit (getResolution()). Auf Sensorereignisse reagieren Mit den beiden Methoden registerListener() und unregisterListener() der Klasse SensorManager können Sie sich über Sensor-Ereignisse informieren lassen sowie entsprechende Benachrichtigungen deaktivieren. registerListener() erwartet ein Objekt des Typs SensorEventListener. Wie

eine

einfache

Implementierung

aussehen

kann,

zeigt

die

Klasse

SensorDemo1. Sie finden das vollständige Projekt SensorDemo1 im Verzeichnis

Quelltexte der Begleit-DVD des Buches. Die App nutzt den Helligkeitssensor eines Geräts und gibt je nach Helligkeit den gemessenen Wert oder den Text sonnig aus. Die Lebenszyklus-Methoden onCreate() und onDestroy() bzw. onStart() und onPause() einer Activity bieten sich an, um SensorEventListener zu registrieren bzw. zu entfernen. public class SensorDemo1 extends Activity { private static final String TAG = SensorDemo1.class.getSimpleName(); private private private private

TextView textview; SensorManager manager; Sensor sensor; SensorEventListener listener;

@Override public void onCreate(Bundle savedInstanceState) {

210

Sensoren

super.onCreate(savedInstanceState); setContentView(R.layout.main); textview = (TextView) findViewById(R.id.textview); manager = (SensorManager) getSystemService(SENSOR_SERVICE); // Ist Helligkeitssensor vorhanden? sensor = manager.getDefaultSensor(Sensor.TYPE_LIGHT); if (sensor == null) { Log.d(TAG, "kein Helligkeitssensor vorhanden"); // Activity beenden finish(); } listener = new SensorEventListener() { @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onSensorChanged(SensorEvent event) { if (event.values.length > 0) { float light = event.values[0]; String text = Float.toString(light); if ( (SensorManager.LIGHT_SUNLIGHT 0) { float light = event.values[0];

218

GPS und ortsbezogene Dienste

String text = Float.toString(light); textview.setText(text); } } }; manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onDestroy() { super.onDestroy(); if (sensor != null) { manager.unregisterListener(listener); } } } Listing 9.4

SensorDemo2.java (geänderte Version)

Der Aufruf der Methode connectSimulator() ist neu. Bevor Sie die App starten, müssen Sie in der Manifestdatei noch die Berechtigung android.permission. INTERNET anfordern. Nun können Sie im Sensor-Simulator-Hauptfenster Temperaturwerte eintragen, die mit minimaler Verzögerung von SensorDemo2 angezeigt werden.

9.2

GPS und ortsbezogene Dienste

Einer der Gründe für die große Beliebtheit von Smartphones und Tablets ist deren Fähigkeit, den aktuellen Standort ermitteln zu können. Wer in einer fremden Stadt schon einmal schnellstmöglich den Bahnhof erreichen oder einen Geldautomaten finden musste, möchte den Komfort, auf entsprechende Apps zurückgreifen zu können, sicherlich nicht mehr missen. Dabei sind die Einsatzgebiete dieser Technik ganz sicher noch lange nicht vollständig ausgelotet. Haben Sie Lust bekommen, sich damit zu beschäftigen? In diesem Abschnitt zeige ich Ihnen, wie Sie die aktuelle Position ermitteln und auf einer Karte anzeigen können. Android bietet komfortable und einfach zu nutzende Programmierschnittstellen an. Lassen Sie Ihrer Kreativität freien Lauf.

219

9.2

9

Sensoren und GPS

9.2.1

Den aktuellen Standort ermitteln

Kopieren Sie das Projekt LocationDemo1, mit dem der Anwender seinen aktuellen Standort ermitteln kann, vom Verzeichnis Quelltexte der Begleit-DVD in Ihren Eclipse-Arbeitsbereich, und importieren Sie es anschließend. Die Klasse LocationDemo1 ermittelt in der Methode onCreate() durch Aufruf von getSystemService(LOCATION_SERVICE) eine Instanz des Typs android. location.LocationManager. Dieses Objekt ermöglicht den Zugriff auf alle ortsbezogenen Funktionen des Systems. Sie können beispielsweise einen Listener registrieren, um unterrichtet zu werden, sobald sich der Standort des Geräts ändert. LocationManager und LocationProvider Positionsdaten werden durch Location Provider zur Verfügung gestellt. Um zu ermitteln, welche dieser Datenlieferanten vorhanden sind, können Sie die LocationManager-Methode getAllProviders() aufrufen. Sie liefert eine Liste mit den Namen der grundsätzlich verfügbaren Provider. Mit getProvider() erhalten Sie eine Instanz des Typs android.location. LocationProvider. Der Rückgabewert von isProviderEnabled() gibt Auskunft darüber, ob der Anwender den korrespondierenden Provider auf der Einstellungsseite Standort und Sicherheit ein- oder ausgeschaltet hat. for (String name : providers) { LocationProvider lp = manager.getProvider(name); Log.d(TAG, lp.getName() + " --- isProviderEnabled(): " + manager.isProviderEnabled(name)); Log.d(TAG, "requiresCell(): " + lp.requiresCell()); Log.d(TAG, "requiresNetwork(): " + lp.requiresNetwork()); Log.d(TAG, "requiresSatellite(): " + lp.requiresSatellite()); } Listing 9.5

Informationen über vorhandene Location Provider ausgeben

Vielleicht fragen Sie sich, warum es mehrere Location Provider gibt. Sie können den Standort eines Geräts auf unterschiedliche Weise ermitteln. Die Nutzung des Global Positioning Systems (GPS) liefert recht genaue Positionen, funktioniert aber nur im Freien zuverlässig und benötigt vergleichsweise viel Strom. Eine andere Möglichkeit besteht darin, Informationen von Sendemasten oder WIFI-Zugangspunkten auszuwerten. Das klappt natürlich nur, wenn das Tablet oder Smartphone in ein Netz eingebucht ist. Beide Varianten haben also spezifi-

220

GPS und ortsbezogene Dienste

sche Vor- und Nachteile. Android bietet deshalb die Möglichkeit, anhand von bestimmten Kriterien den am besten geeigneten Location Provider zu ermitteln. Das folgende Beispiel liefert den Namen eines Providers, der die Position nur grob auflöst, dafür aber mit einem niedrigen Energieverbrauch auskommt: Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_COARSE); criteria.setPowerRequirement(Criteria.POWER_LOW); String provider = manager.getBestProvider(criteria, true); Listing 9.6

Provider mit geringem Verbrauch suchen

Mit dem Namen des am besten geeigneten Location Providers können Sie, wie gewohnt, die LocationManager-Methode getProvider() aufrufen. Positionsänderungen abfragen Es gibt zwei Möglichkeiten, den aktuellen Standort zu ermitteln. Die Methode getLastKnownLocation() des Location Managers liefert die letzte bekannte Posi-

tion, die ein Location Provider ermittelt hat. Diese kann – muss aber nicht – dem aktuellen Aufenthaltsort entsprechen. Insofern bietet sich diese Methode vor allem an, um dem Anwender einen ersten Hinweis darauf zu geben, wo er sich befindet (oder zuletzt befunden hat). Beachten Sie aber, dass getLastKnownLocation() auch null liefern kann. Die zweite Variante besteht darin, einen LocationListener zu registrieren. Dieser wird bei Positionsänderungen aufgerufen. Die hierfür zuständige Methode requestLocationUpdates() steht in zahlreichen Ausprägungen zur Verfügung. Beispielsweise können Sie steuern, wie viel Zeit mindestens zwischen zwei Aufrufen der Callback-Methode onLocationChanged() liegen sollte. public class LocationDemo1 extends Activity { private static final String TAG = LocationDemo1.class.getSimpleName(); private TextView textview; private LocationManager manager; private LocationListener listener; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); textview = (TextView) findViewById(R.id.textview);

221

9.2

9

Sensoren und GPS

// LocationManager-Instanz ermitteln manager = (LocationManager) getSystemService(LOCATION_SERVICE); // Liste mit Namen aller Provider erfragen List providers = manager.getAllProviders(); // Infos zu Location Providern ausgeben for (String name : providers) { LocationProvider lp = manager.getProvider(name); Log.d(TAG, lp.getName() + " --- isProviderEnabled(): " + manager.isProviderEnabled(name)); Log.d(TAG, "requiresCell(): " + lp.requiresCell()); Log.d(TAG, "requiresNetwork(): " + lp.requiresNetwork()); Log.d(TAG, "requiresSatellite(): " + lp.requiresSatellite()); } // Provider mit grober Auflösung und niedrigem Energieverbrauch Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_COARSE); criteria.setPowerRequirement(Criteria.POWER_LOW); // Namen ausgeben String name = manager.getBestProvider(criteria, true); Log.d(TAG, name); // LocationListener-Objekt erzeugen listener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.d(TAG, "onStatusChanged()"); } @Override public void onProviderEnabled(String provider) { Log.d(TAG, "onProviderEnabled()"); } @Override public void onProviderDisabled( String provider) {

222

GPS und ortsbezogene Dienste

Log.d(TAG, "onProviderDisabled()"); } @Override public void onLocationChanged( Location location) { Log.d(TAG, "onLocationChanged()"); if (location != null) { String s = "Breite: " + location.getLatitude() + "\nLänge: " + location.getLongitude(); textview.setText(s); } } }; } @Override protected void onStart() { super.onStart(); Log.d(TAG, "onStart()"); manager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 3000, 0, listener); } @Override protected void onPause() { super.onPause(); Log.d(TAG, "onPause()"); manager.removeUpdates(listener); } } Listing 9.7

Auszug aus LocationDemo1.java

Die Klasse LocationDemo1 registriert einen LocationListener für den GPS-basierenden Location Provider. Wenn Sie das Projekt LocationDemo1 im Emulator ausprobieren, können Sie Positionswechsel simulieren, indem Sie eine telnet-Verbindung aufbauen und das Kommando geo fix senden. Komfortabler ist die Eingabe allerdings über die Emulator Control der DDMS-Perspektive möglich.

223

9.2

9

Sensoren und GPS

Um auch die App LocationDemo2, die ich Ihnen im folgenden Abschnitt vorstellen werde, ausprobieren zu können, sollten Sie ein Android Virtual Device (AVD) auf der Basis der Google-APIs erstellen. Zum Zeitpunkt der Drucklegung stürzen alle AVDs mit Google-API und API-Level 9 oder höher ab beim Versuch, Positionsdaten zu senden. Falls dieses Problem bei Ihnen auftritt, rate ich Ihnen, ein virtuelles Gerät mit Google-API und API-Level 8 zu erzeugen. Meiner Erfahrung nach gibt es dann keine Probleme. Tipp Je nachdem, welche bzw. welchen Location Provider Sie verwenden möchten, müssen Sie in der Manifestdatei Ihrer App die Berechtigungen android.permission. ACCESS_COARSE_LOCATION (Netzwerk) oder android.permission.ACCESS_FINE_ LOCATION (GPS) anfordern.

Die Klasse android.location.Location getLastKnownLocation() und onLocationChanged() liefern Instanzen der Klasse android.location.Location. Sie repräsentieren geografische Positionen (angegeben durch Länge und Breite) zu einem bestimmten Zeitpunkt. Informationen über Höhe, Geschwindigkeit und Richtung können zusätzlich vorhanden sein. Die Erde wird in 360 Längen- und 180 Breitengrade unterteilt. Da letztere vom Äquator aus gezählt werden, liegen die beiden Pole bei 90° Nord bzw. Süd. Der Nullmeridian teilt die Längengrade in westlicher und östlicher Richtung.

Innerhalb eines Location-Objekts werden Länge und Breite als double gespeichert. Die textuelle Darstellung hängt von der gewünschten Genauigkeit ab. Aus diesem Grund können Sie mit der Methode convert() eine Zeichenkette in eine Fließkommazahl umwandeln. Auch die andere Richtung ist möglich. Hierzu ein Beispiel: Die ungefähre geografische Position von Nürnberg ist 49° 27' Nord und 11° 5' Ost. Grad und Minuten werden durch einen Doppelpunkt getrennt und als Zeichenkette an convert() übergeben: Location locNuernberg = new Location(LocationManager.GPS_PROVIDER); double latitude = Location.convert("49:27"); locNuernberg.setLatitude(latitude); double longitude = Location.convert("11:5"); locNuernberg.setLongitude(longitude); Log.d(TAG, "latitude: " + locNuernberg.getLatitude()); Log.d(TAG, "longitude: " + locNuernberg.getLongitude()); Listing 9.8

224

Umwandlung von String- in double-Werte

GPS und ortsbezogene Dienste

Soll aus einem double-Wert eine Zeichenkette bestehend aus Grad und Minuten erzeugt werden, übergeben Sie diesen an convert(). Der zweite Parameter ist Location.FORMAT_MINUTES.

9.2.2

Positionen in einer Karte anzeigen

In diesem Abschnitt zeige ich Ihnen, wie Sie den aktuellen Standort auf einer Karte visualisieren können. Die hierfür verwendete Klasse com.google.android. maps.MapView nimmt Ihnen die gesamte Kommunikation mit dem Dienst Google Maps ab. Allerdings ist sie nicht Teil der Standard-Android-Klassenbibliothek und damit nicht notwendigerweise auf jedem Android-Gerät vorhanden. Außen vor bleiben vor allem preiswertere Portable Media Player. Die meisten Smartphones haben an dieser Stelle aber keine Probleme. Der Maps-API-Schlüssel Damit eine App Google Maps nutzen kann, muss sie einen Schlüssel übermitteln. Sie erhalten diesen kostenlos, indem Sie sich auf der Seite http://code.google.com/ intl/de-DE/android/add-ons/google-apis/maps-api-signup.html registrieren. Im Rahmen dieser Registrierung müssen Sie den Nutzungsbedingungen des Dienstes Google Maps zustimmen. Der Maps-API-Schlüssel ist an das Zertifikat gebunden, mit dem Sie Ihre Apps signieren. Während der Entwicklung verwenden Sie automatisch ein spezielles Debug-Zertifikat. Dieses befindet sich in der Datei debug.keystore. Wo diese abgelegt wird, hängt vom Betriebssystem Ihres Entwicklungsrechners ab. Unter Windows 7 ist dies der Ordner .android im Heimatverzeichnis des angemeldeten Benutzers. Öffnen Sie die Eingabeaufforderung bzw. eine Shell, und wechseln Sie in das Verzeichnis, in dem debug.keystore liegt. Geben Sie nun die folgende Anweisung in einer Zeile ein. Sie erzeugt einen MD5-Fingerabdruck des Entwicklungszertifikats. keytool -list -alias androiddebugkey -keystore debug.keystore -storepass android -keypass android

Damit das funktioniert, muss das Verzeichnis bin des Java Development Kits im Standardsuchpfad enthalten sein. Tragen Sie nun die 16 durch Doppelpunkt getrennten Hexadezimalwerte in das Eingabefeld der Registrierungsseite ein. Im Anschluss daran erhalten Sie von Google einen Maps-API-Schlüssel. Kopieren Sie diesen in eine beliebige Textdatei, oder speichern Sie die HTML-Seite auf Ihrem Rechner.

225

9.2

9

Sensoren und GPS

Tipp Schlüssel, die aus dem Fingerabdruck eines Entwicklerzertifikats generiert wurden, funktionieren nur im Rahmen der Entwicklung. Wenn Sie eine App im Android Market anbieten möchten, die Google Maps nutzt, müssen Sie einen zusätzlichen API-Schlüssel aus dem Fingerabdruck Ihres Produktionszertifikats generieren.

MapViews anzeigen Legen Sie in Eclipse ein neues Android-Projekt an, und nennen Sie es LocationDemo2. Tragen Sie com.thomaskuenneth.locationdemo2 als Paketname ein, und lassen Sie die Activity LocationDemo2 erzeugen. Wie Sie bereits wissen, gehört die Klasse MapActivity nicht zum Standardfunktionsumfang von Android, sondern ist Teil der Google-APIs. Aus diesem Grund setzen Sie bei Build Target ein Häkchen vor den Eintrag Google APIs mit dem API-Level 8. Nachdem Sie den Projektassistenten geschlossen haben, müssen Sie in der Manifestdatei noch eintragen, dass Ihre App die Google-Maps-Bibliothek verwendet und die Berechtigungen android.permission.ACCESS_FINE_LOCATION sowie android.permission.INTERNET benötigt. Das Attribut android:name des Elements verweist auf das Paket com.google.android.maps. Damit können Sie Google Maps und die Klasse MapActivity in LocationDemo2 nutzen.

226

GPS und ortsbezogene Dienste

Listing 9.9

Manifestdatei des Projekts »LocationDemo2«

Der Inhaltsbereich einer MapActivity wird durch Aufruf der Methode setContentView() gesetzt. Die Layoutdatei main.xml von LocationDemo2 ist sehr einfach gehalten. Das einzige Element wird bildschirmfüllend angezeigt. Dessen Attribut android:apiKey muss den Google-Maps-API-Schlüssel enthalten, der Ihnen im Rahmen des Registrierungsprozesses übermittelt wurde. Listing 9.10

main.xml

Die Klasse LocationDemo2 leitet von com.google.android.maps.MapActivity ab. In onCreate() wird das in der Datei main.xml abgelegte Layout entfaltet. Außerdem registriert die Activity einen LocationListener. In seiner Methode onLocationChanged() wird der aktuelle Standort in eine Instanz des Typs com.google.android.maps.GeoPoint gepackt und an die Methode setCenter() von einem MapController übergeben. package com.thomaskuenneth.locationdemo2; import import import import import

android.location.Location; android.location.LocationListener; android.location.LocationManager; android.os.Bundle; android.util.Log;

import import import import

com.google.android.maps.GeoPoint; com.google.android.maps.MapActivity; com.google.android.maps.MapController; com.google.android.maps.MapView;

227

9.2

9

Sensoren und GPS

public class LocationDemo2 extends MapActivity { private static final String TAG = LocationDemo2.class.getSimpleName(); private LocationManager manager; private LocationListener listener; private MapController mapController; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Location Manager ermitteln manager = (LocationManager) getSystemService(LOCATION_SERVICE); // LocationListener definieren listener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.d(TAG, "onStatusChanged()"); } @Override public void onProviderEnabled(String provider) { Log.d(TAG, "onProviderEnabled()"); } @Override public void onProviderDisabled( String provider) { Log.d(TAG, "onProviderDisabled()"); } @Override public void onLocationChanged( Location location) { Log.d(TAG, "onLocationChanged()"); // Koordinaten umwandeln int lat = (int) (location.getLatitude() * 1E6); int lng = (int) (location.getLongitude() * 1E6); GeoPoint point = new GeoPoint(lat, lng); mapController.setCenter(point);

228

GPS und ortsbezogene Dienste

} }; // Zoom aktivieren MapView mapView = (MapView) findViewById(R.id.mapview); mapView.setBuiltInZoomControls(true); // MapController ermitteln mapController = mapView.getController(); } @Override protected void onStart() { super.onStart(); Log.d(TAG, "onStart()"); manager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 3000, 0, listener); } @Override protected void onPause() { super.onPause(); Log.d(TAG, "onPause()"); manager.removeUpdates(listener); } @Override protected boolean isRouteDisplayed() { return false; } } Listing 9.11

LocationDemo2.java

Die Anweisung mapView.setBuiltInZoomControls(true); sorgt dafür, dass der Benutzer in die Karte hinein- bzw. herauszoomen kann. Die Klasse MapView (sie stellt die Karte letztlich dar) verwendet für Positionsangaben nicht die Ihnen aus dem vorherigen Abschnitt bereits bekannten Locations, sondern Instanzen von GeoPoint. Länge und Breite werden je als int gespeichert. Die Umrechnung erfolgt, indem Sie den double-Wert aus Location mit 1E6 multiplizieren. Denken Sie daran, vor dem Start von LocationDemo2 in der Datei main.xml Ihren Entwicklerschlüssel dem Attribut android:apiKey zuzuweisen. Nutzen Sie die Perspektive DDMS, um simulierte Positionsdaten an die in Abbildung 9.5 gezeigte App zu senden.

229

9.2

9

Sensoren und GPS

Abbildung 9.5

Die App »LocationDemo2«

Weiterführende Informationen zur Nutzung von Google Maps und ortsbezogenen Diensten finden Sie im Dokument Location and Maps.2

2 http://developer.android.com/guide/topics/location/index.html

230

Index .3gp 308 .wav 329 @drawable 89, 207 @string 87, 207 _ID 376

A ACCESS_COARSE_LOCATION 224 ACCESS_FINE_LOCATION 224, 226 ACCESS_NETWORK_STATE 176 Account 385 AccountManager 381, 384, 385, 386 AccountManagerCallback 386 action 100 ACTION_BOOT_COMPLETED 190 ACTION_CALL 172 ACTION_CHECK_TTS_DATA 325 ACTION_CHOOSER 193 ACTION_DIAL 172 ACTION_EDIT 389 ACTION_IMAGE_CAPTURE 342, 344 ACTION_INSERT 102 ACTION_MEDIA_BUTTON 334, 336 ACTION_RECOGNIZE_SPEECH 332 ACTION_SEND 348, 351 ACTION_SET_ALARM 391, 393 ACTION_SET_WALLPAPER 192 ACTION_VIEW 348 ACTION_WEB_SEARCH 101 Activity 37, 39, 51, 70, 73, 85, 87, 91, 100, 108, 133, 138, 143, 148, 194, 209, 294, 341, 344, 354, 384, 389, 395 Activity Manager 27 Adapter 66, 309 adb 82 add() 309 addAccount() 385 addCallback() 353, 356 addHeader() 389 addPreferencesFromResource() 137, 205 addRow() 299 addTab() 136 addView() 120 ADT 27, 35, 37, 39, 46, 50, 78, 132

AIDL 163, 164 AlarmClock 391 AlarmManager 395 AlertDialog 140, 143 AlertDialog.Builder 140 Alternative Ressourcen 126 AnalogClock 116 Android 31 Android Debug Bridge 213, 253 Android Development Tools 씮 ADT Android Device Chooser 42 Android Inc. 20 Android Interface Definition Language 163 Android Market 23, 30, 40, 60, 69, 77, 79, 89, 212, 226, 357 Android Runtime 26 Android SDK 27, 28 Android Virtual Device 씮 AVD android.appwidget.provider 182 android:icon 294 android:label 294 ANDROID_ID 175 AndroidManifest.xml 39, 47, 86 ANR 153 Apache Harmony 씮 Harmony apiKey 227, 229 API-Schlüssel 226 apk 77 APP_ID 274 application 39, 74, 87, 106, 180 Application Framework 26 Application not responding 153 Application Package 77 APPWIDGET_UPDATE 182 AppWidgetManager 187 AppWidgetProvider 182, 185, 187, 190 Arbeitsbereich 35, 61 ArrayAdapter 66, 309 ArrayList 69 Aspect Ratio 130 assets 37, 39 attachAuxEffect() 321 AudioEffect 319 AudioManager 335

411

Index

Auflösung 130 Auth Token 385 Auth Token-Typ 386 Authority 284 authority 396 AVD 30, 40, 224

B Back Stack 86, 98 background 121 BassBoost 319 Benutzeroberfläche 64 Bildschirmgröße 130 bin 28 BIND_WALLPAPER 197 Binder 161 bindService() 163, 166 Bitmap 191, 345, 350 BOOKMARK 277, 278 BookmarkColumns 277 Bornstein, Dan 25 Broadcast Receiver 103 BroadcastReceiver 182, 336 Browser 277, 279 Build Target 36 Button 49, 114, 317 Bytecode 24

C Cache Flush 151 Call Log 156, 171, 176, 272 CALL_PHONE 172 CALL_STATE_IDLE 173 CALL_STATE_OFFHOOK 173 CALL_STATE_RINGING 173 Callback 365 CallLog 177 CAMERA 357, 362 Camera 356 CameraInfo 358 Canvas 192, 350 CATEGORY_BROWSABLE 101 center 121 CHECK_VOICE_DATA_PASS 325 CheckBox 118 CheckBoxPreference 138 Codd, E. F. 251

412

ColorMatrix 350 com.google 385 CommonDataKinds 372 configure 190 ConnectivityManager 176 connectSimulator() 219 CONTACT_ID 372, 375 Contacts 370, 371 ContactsContract 370, 371, 372 content 396 Content Provider 27, 272, 376 Content Resolver 380, 395 content:// 284 CONTENT_ITEM_TYPE 372, 375 CONTENT_URI 273, 275, 280, 285, 297, 370, 372 ContentObserver 157, 180, 183, 185 ContentProvider 284, 285, 297 ContentResolver 178, 179, 271, 272, 273, 275, 276, 277, 279, 280, 282, 370 ContentValues 274, 275, 277, 280, 376 Context 138, 172, 178, 187, 190, 209, 272 convert() 224, 225 convertView 115 Core Libraries 26 Create Activity 37, 92 create() 140 CREATE_LIVE_FOLDER 294, 295 createChooser() 352 createNewFile() 314 Cupcake 21, 181, 291 currentThread() 152 Cursor 271, 276, 282 CursorAdapter 282 Custom Locale 89

D Dalvik 23, 25, 161 Dalvik Debug Monitor Server 씮 DDMS Dalvik Executable 24 Danger, Inc. 21 Data 370 Date 308 Datenbankmanagementsystem 252, 254 Datenfeld 251 Datensatz 251 DatePicker 126, 139

Index

DatePickerDialog 139, 140 DDMS 174, 223, 229 debuggable 74 delete() 272, 275, 279, 282, 289, 297, 345 Density-independent Pixel 씮 dp DESCRIPTION 303 Developer Console 77, 80 Dialog 143 DialogFragment 109 Donut 22, 130, 322 dp 132, 189 drawable-hdpi 89, 132 drawable-ldpi 89, 132 drawable-mdpi 132 drawBitmap() 350 dx 25

E Eclair 22 Eclipse 27 EditText 49, 55, 114 EditTextPreference 138, 139 Eingabeaufforderung 31, 253 Emulator 31, 41 Emulator Control 175, 179, 223 enabled 106 Environment 311 Event 372, 375 Event Dispatching Thread 153 exported 106, 158, 162, 207 EXTRA_HOUR 391 EXTRA_LANGUAGE 333 EXTRA_LIVE_FOLDER_ICON 295 EXTRA_LIVE_FOLDER_NAME 295 EXTRA_MESSAGE 391 EXTRA_MINUTES 391 EXTRA_SKIP_UI 391

F Fibonacci 149 Fibonacci-Folge 74 File 308, 314 FilenameFilter 310 fill_parent 50 findViewById() 69, 115 finish() 98, 295, 325

FORMAT_MINUTES 225 Fragment 22, 107, 109 FrameLayout 114, 117, 120 FREQUENCY 274 Froyo 22, 245

G G1 13, 19, 21, 126, 132 gen 39 GeoPoint 227, 229 GET_ACCOUNTS 389 getAccountsByType() 385 getAction() 194 getAllNetworkInfo() 176 getAllProviders() 220 getAppWidgetIds() 187 getAudioSessionId() 319 getAuthToken() 385, 386 getBinder() 164 getBitmap() 345, 348 getCameraInfo() 357 getColumnIndex() 274 getContentResolver() 178, 272, 276, 277 getCount() 69 getData() 347 getDefaultSensor() 210 getDesiredMinimumHeight() 191 getDesiredMinimumWidth() 191 getDeviceId() 175 getExternalStorageState() 311 getHeight() 115 getId() 321 getInstalledPackages() 396 getInstance() 187, 190 getIntent() 393 getIntExtra() 394 getItem() 69 getKeyCode() 337 getLastKnownLocation() 221, 224 getListView() 66, 135 getMainLooper() 328 getMaximumRange() 210 getMeasuredHeight() 115 getMeasuredWidth() 115 getName() 152 getNetworkInfo() 176 getPaddingBottom() 116 getPaddingLeft() 116

413

Index

getPaddingRight() 116 getPaddingTop() 116 getPower() 210 getProvider() 220 getResolution() 210 getResources() 91 getResult() 386 getRoundedStrength() 319 getSensorList() 210 getService() 161 getStrengthSupported() 319 getString() 55, 91, 138 getStringArrayListExtra() 333 getStringExtra() 394 getSupportedPreviewSizes() 356 getSystemService() 173, 209, 220 getType() 284, 286, 297 getView() 69, 115 getWidth() 115 getWritableDatabase() 287 Gingerbread 22, 316, 357, 391 Global Positioning System 씮 GPS Google APIs Console 386 Google Maps 225 Google-APIs 226 Google-Konto 380 Google-Maps-API 227 GPS 220 gravity 120, 123

Input Method Framework 21 inputType 56 insert() 272, 274, 277, 280, 284, 287, 297, 376, 377 INTENT 303 Intent 99, 135, 160, 192, 334, 336, 348, 351, 389 explizites 100, 101 implizites 100, 102 INTENT_ACTION_STILL_IMAGE_CAMER A 341, 342 INTENT_ACTION_VIDEO_CAMERA 341, 342 Intent-Filter 100, 165, 351 intent-filter 87, 92, 100 INTERNET 219, 226, 295, 389 interrupt() 150 InterruptedException 150 invalidateOptionsMenu() 145 isAlive() 149 isAvailable() 176 isChecked() 119 isLanguageAvailable() 327 isLongPress() 337 isMusicActive() 335 isProviderEnabled() 220 isRoaming() 176

H

Java Development Kit 27 Java Virtual Machine 24 javac 27 JDK 27 Just-in-time-Compiler 24 JVM 24

handleMessage() 164, 167 Handler 155, 167 Harmony 26, 148 HashMap 327 Hashtable 63 hierarchyviewer 124 Hiptop 21 Honeycomb 22, 389, 391 HttpGet 389

I IBinder 156, 161 icon 77, 89 Images 345 ImageView 345 IN_VISIBLE_GROUP 371

414

J

K KEY_AUTHTOKEN 386 KeyEvent 336 Keystore 78 keytool 79, 225 Kontextmenü 145, 266

L LABEL 373 label 87

Index

LANGUAGE_MODEL_FREE_FORM 333 LANGUAGE_MODEL_WEB_SEARCH 333 Layout 48 layout 49, 113 layout_above 125 layout_below 65 layout_gravity 121 layout_height 49, 114 layout_toLeftOf 125 layout_toRightOf 65 layout_weight 123 layout_width 49, 114 Layoutdatei 48 LayoutInflator 69 LinearLayout 49, 65, 114, 120, 124, 353 Linux 24, 147 ListActivity 65, 92, 135 ListAdapter 67, 135 listen() 173 LISTEN_CALL_STATE 173 LISTEN_NONE 173 listFiles() 310 ListFragment 109 ListPreference 208 ListView 64 Live Folder 291 Live Wallpaper 22 LiveFolders 303 Location 224, 229 LOCATION_SERVICE 220 LocationListener 221, 223, 227 LocationManager 220 LocationProvider 220 Log 71 LogCat 70, 71, 90, 149, 150, 152, 154, 156, 272, 276, 334, 369, 371, 374, 392, 395 LogView 75 Looper 328

M Magic 126, 132 Magic Cap 21 MAIN 101 Mainthread 152 manifest 39, 359 Manifestdatei 294, 351, 391, 397

MapActivity 226 MapController 227 MapView 225, 227, 229 MatrixCursor 299 Media 345 MediaPlayer 313, 314, 317, 320 MediaRecorder 314, 315, 363 MediaStore 341, 342, 344, 345 Message 164 Messenger 164, 167 MIME-Typ 351 MIMETYPE 375 Miner, Richard 21 minHeight 189 minSdkVersion 40, 87, 107, 131 minWidth 189 MODIFY_AUDIO_SETTINGS 320 moveToNext() 274 Multitasking 147 präemptives 147

N NAME 303 name 45, 100 Notification Manager 27 NullPointerException 274

O obtain() 166 OHA 20 onActivityCreated() 112 onActivityResult() 103, 325, 332, 333, 344, 345, 347 onAttach() 112 onBind() 156, 161 onCallStateChanged() 173 onChange() 157, 180 onClick() 154, 155, 310, 341 OnClickListener 55, 118, 310, 341, 359 OnCompletionListener 313, 317 onContextItemSelected() 145, 282 onCreate() 53, 93, 112, 135, 157, 295, 326, 393 onCreateContextMenu() 145 onCreateDialog() 140, 142, 143 onCreateEngine() 198 onCreateOptionsMenu() 143, 145

415

Index

onCreateView() 109, 110 OnDateSetListener 140 onDestroy() 112, 157, 180, 185, 210, 317, 323, 324 onDestroyView() 110 onDetach() 112 onDisabled() 185 onDraw() 114 onEnabled() 185 onInfo() 366 OnInfoListener 366 onInit() 326, 328 OnInitListener 326 OnItemClickListener 66 onLocationChanged() 221, 224 onOptionsItemSelected() 144 onPause() 95, 98, 112, 210, 310, 335, 354, 356 onPictureTaken() 361 onPrepareDialog() 142 onPrepareOptionsMenu() 145 onReceive() 105, 185, 336 onRestart() 98 onResume() 97, 335, 354, 358 onSaveInstanceState() 95 onSensorChanged() 215 onServiceConnected() 163 onShutter() 361 onStart() 95, 97, 152, 163, 166, 210 onStartCommand() 160 onStop() 112 onUpdate() 186, 188, 190 onUtteranceCompleted() 328 OnUtteranceCompletedListener 328 Open Handset Alliance 20 Open Source 20 open() 356 Optionsmenü 85, 143 orientation 123 Orientierungswechsel 93 OutOfMemoryError 348

P package 87, 100 Package Explorer 38, 78, 127 PackageInfo 396 Parameters 362 Parcelable 94

416

PATH 28, 29, 82 PendingIntent 395 permission 106, 158 PhoneStateListener 177 Pico 322 PictureCallback 360 Pixeldichte 130 Plattform 23 post() 155, 328 postDelayed() 198, 208 Präemptives Multitasking 147 PreferenceActivity 92, 205 PreferenceCategory 138 prepare() 313, 314 PresetReverb 321 process 107, 158, 159 provider 295, 296, 297 put() 274 putExtra() 102, 295, 333, 344, 389, 391

Q query() 271, 272, 274, 276, 284, 287, 297, 299, 372, 395

R R 39, 46 R.string 61 RatingBar 116 RawContacts 370, 376 READ_CALENDAR 397 READ_CONTACTS 177, 370 READ_HISTORY_BOOKMARKS 278 READ_PHONE_STATE 174, 175 READ_USER_DICTIONARY 275 RECEIVE_BOOT_COMPLETED 105 receiver 106, 182, 186 RecognizerIntent 332 RECORD_AUDIO 362 recycle() 348 registerForContextMenu() 145 registerListener() 210 registerMediaButtonEventReceiver() 335 registerReceiver() 105 Relationales Datenbanksystem 251 RelativeLayout 64, 124 release() 317, 319, 356 Remote Procedure Call 161

Index

RemoteView 189 removeCallback() 354 removeCallbacks() 202 replyTo 164, 167 Request Code 103 requestCode 345 requestLocationUpdates() 221 res 37, 49, 88, 113 resource 182 Resource Manager 27 resources 203 RESULT_OK 345 resultCode 345 Rubin, Andy 21 Run Configuration 40 run() 149 Runnable 149, 155, 199

S saveBookmark() 279 Schlüssel 79 ScrollView 131 SDK Manager 29 Sears, Nick 21 Secondary Market 77, 81 Seitenverhältnis 130 send() 166 Sensor 209 Sensor Simulator 212 SENSOR_SERVICE 209 SensorEventListener 210, 215 SensorManager 209, 212 Service 156, 164, 179, 209 service 158, 159, 197 ServiceConnection 163 set() 395 SET_ALARM 391 SET_WALLPAPER 191, 194 setAudioEncoder() 314 setAudioSource() 314 setAuxEffectSendLevel() 321 setBitmap() 191, 194 setBuiltInZoomControls() 229 setCenter() 227 setChecked() 119 setContentView() 93, 114, 130, 133, 227, 326 setData() 296

setDataSource() 313 setEnabled() 319 setImageBitmap() 345 setMaxDuration() 366 setMaxFileSize() 366 setOnClickListener() 119, 359 setOnClickPendingIntent() 188 setOnItemClickListener() 135 setOnUtteranceCompletedListener() 328 setOutputFormat() 314 setPadding() 116 setPreviewDisplay() 365 setPreviewSize() 356 setRequestedOrientation() 344 setResource() 190 setResult() 295 setRingerMode() 335 setSaturation() 350 setStrength() 319 setTag() 69 setText() 110 setTextViewText() 189 Settings.Secure 175 settingsActivity 207 setType() 354 Shell 31, 253 showDialog() 140, 143 shutdown() 324, 329 ShutterCallback 360 Simple API Access 386 SimpleCursorAdapter 135 SIP 22 sleep() 150 Software Development Kit 씮 Android SDK speak() 327 SQL 252 SQLite 251, 252, 273 SQLiteDatabase 275 SQLiteOpenHelper 280 SQLiteQueryBuilder 287 src 38 Stacktrace 73 start() 313, 314, 319 START_DATE 373 START_NOT_STICKY 160 START_REDELIVER_INTENT 160 START_STICKY 160 startActivity() 101, 172, 192, 348, 352

417

Index

startActivityForResult() 103, 325, 333, 342, 345 Starter Package 28 startForeground() 185 startPreview() 354 startService() 158, 159, 160, 180, 183 stop() 150, 315 stopSelf() 159 stopSelfResult() 159 stopService() 159, 183 string 45 strings.xml 39, 45, 63, 87 Structured Query Language 252 SuperNotCalledException 93 supports-screens 131 Surface Manager 25 surfaceCreated() 356 SurfaceHolder 353, 365 SurfaceHolder.Callback 353 SurfaceView 353, 355, 363, 365 Swing 153 synchronized 152 synthesizeToFile() 329

T TabActivity 135 TabContentFactory 136 TabHost 135, 136 TabSpec 135, 136 takePicture() 360, 361 targetSdkVersion 107, 131 TELEPHONY_SERVICE 173 TelephonyManager 175 Telnet 174, 223 TextToSpeech 324, 327 TextToSpeech.Engine 325 TextView 49, 110, 309 Thread 148, 149, 150, 152 thumbnail 207 Tierkreiszeichen 63 TITLE 278 Toast 257, 281 toString() 308 Treiber 75 Tupel 251 TYPE 373 TYPE_ALL 210 TYPE_WIFI 176

418

U UI-Thread 153, 155 Umgebungsvariable 28, 31, 82 Unbekannte Herkunft 82 unbindService() 163 unregisterListener() 210 unregisterMediaButtonEventReceiver() 335 UnsupportedOperationException 297 update() 271, 272, 282, 284, 288, 297 updatePeriodMillis 190 URI 285, 286, 288, 289, 296, 297 UriMatcher 285, 286 URL 277, 278 USB-Debugging 76 USB-Port 75 USE_CREDENTIALS 389 User Credentials 385 UserDictionary 275 UserDictionaryDemo 272 uses-feature 205, 212 uses-library 226 uses-permission 105 uses-sdk 39, 87

V values 39, 45, 46, 88 values-en 46 values-fr 46 versionCode 87 versionName 87 View 26, 48, 114 ViewGroup 48, 51, 119 ViewHolder 69 Virtual Devices 30 Virtualizer 320, 321 Virtuelle Maschine Dalvik 24 VISITS 277, 278 VoIP 22 volatile 151

W wallpaper 197, 207 WallpaperManager 190 WallpaperService 197 weightSum 123

Index

White, Chris 21 Widgets 22 Wireframe 47, 64 withAppendedPath() 282 WORD 274 Words 273 Workspace 씮 Arbeitsbereich wrap_content 50 WRITE_CALENDAR 397 WRITE_CONTACTS 179, 377 WRITE_EXTERNAL_STORAGE 362

WRITE_HISTORY_BOOKMARKS 278 WRITE_USER_DICTIONARY 275

Y yield() 149

Z Zurück-Taste 86

419