Start Magazin Workshop: Einstieg in die Android-Programmierung mit Android Wear – Teil 1

Workshop: Einstieg in die Android-Programmierung mit Android Wear – Teil 1

Programmieren ist cool und Android Wear ist cool. Was liegt da näher, als die beiden Dinge miteinander zu kombinieren und eine App für die tollen Smart Watches mit Android Wear an Bord zu programmieren. In unserem zweiteiligen Workshop zeigen wir dir, wie das funktioniert. Dabei lernst du ganz nebenbei auch noch die Grundlagen von Android Studio.

Im Nachfolgenden werde ich euch einige Basics zur Programmierung mit Android bzw. spezieller zu Android Wear geben. Es sind leichte Grundkenntnisse von Java und Android von Nöten, um alles zu verstehen. Der ergänzende Code ist lauffähig und es kann nach Belieben mit ihm herumgespielt werden, sodass man auch mit wenigen Vorkenntnissen ein bisschen basteln kann.

Es empfiehlt sich, den Quellcode als ZIP-Datei herunterzuladen und das Projekt in AndroidStudio oder IntelliJ zu öffnen, sodass du begleitend sehen kannst, was wir hier in dem Tutorial machen. Alternativ kannst du es natürlich auch mit git clonen (sofern installiert), oder die ‘Checkout from Version Control‘ Funktion von IntelliJ/AndroidStudio nutzen. Der Code ist sehr stark kommentiert, sodass das optimale Verständnis überall beschrieben steht, was passiert.

Wenn du nicht direkt weißt, wie man Android Studio und das Android SDK installiert, findest du super Anleitungen auf der Developer-Seite von Google: https://developer.android.com/sdk/index.html. Einen Artikel zur Installation des Android SDK, der allerdings schon etwas älter ist, findest du auch im Android-User-Archiv.

Über den Autor: Max Muth ist Informatik-Student an der Technischen Universität München. Mit vielen Themen der Informatik beschäftigt er sich schon länger, teils auch weit vor seinem Studium. Hierzu zählen hauptsächlich Web Development und Web Design, seit längerem entwickelt Max aber auch Android-Apps. Eines seiner aktuellsten Projekte ist der Tank Navigator, der dir die billigste und nächste Tankstelle in der Umgebung anzeigt.

Android Wear “Apps”

Was ist denn eigentlich eine Wear “App”? Grundsätzlich gibt es mehrere Möglichkeiten, wie man als Entwickler mit Smartwatches umgehen kann:

  1. Eine Erweiterung der Smartphone App für die Uhr: Notifications, welche die App auf dem Smartphone erstellt, werden grundsätzlich automatisch auf die Uhr weitergeleitet. Diese können aber für Uhren angepasst, optimiert und erweitert werden. Zum Beispiel lassen sich mehrere “Screens” hinzufügen, die man dann durch horizontale Wischgesten auf der Uhr wechseln kann, um mehr Inhalt (oder Reaktionsmöglichkeiten wie Antworten, Archivieren, oder ähnliches) übersichtlicher darzustellen. Auf dem Handy würden diese Screens dann nicht angezeigt werden. Details auf developer.android.com.
  2. Eine App-Komponente erstellen, die direkt auf der Uhr läuft und die der Nutzer ohne sein Smartphone komplett bedienen kann. Das intuitivste Beispiel sind eingebaute Apps wie die Stoppuhr oder Google Play Music. (developer.android.com)

 

Unsere App zeigt die Zeit an

Wir machen eine Produktivitäts-App, welche dich in regelmäßigen Abständen an die Uhrzeit erinnert. Dies kann zum Beispiel hilfreich sein, weil die Zeit nicht “wie im Flug” vorüber geht, sondern man immer einen Überblick hat, wie viel Zeit vergangen ist, und was man in der Zeit erreicht (oder eben nicht erreicht) hat. Somit lässt sich effektiver Arbeiten, als mit einer gewöhnlichen Uhr.

Quellcode zum Workshop: Den Source Code zum Projekt findest du auf Github unter der URL: https://github.com/mammuth/Time-Reminder-Wear-App

0. Übersicht

Eine kurze Übersicht über das Projekt, die Erklärungen folgen im Verlauf des Artikels.
Eine kurze Übersicht über das Projekt, die Erklärungen folgen im Verlauf des Artikels.

Ausführliche Details und Erklärungen folgen im Verlauf des Artikels und im Quellcode. Die kurze Auflistung an diesem Punkt dient nur der groben ersten Übersicht.

Das Projekt teilt sich in zwei Module auf: wear und mobile. Innerhalb des mobile Moduls haben wir die folgenden vier Klassen:

  1. EinstellungsActivity (Link zur Klasse in Github): Dies ist die Haupt-Acitivty der App auf dem Handy. Hier ist die Anzeige des Status in Form eines Switches eingebaut.
  2. ErinnerungsVerwalter: Diese Klasse dient als Schnittstelle zur Verwaltung von Androids AlarmManager. Hier wird die Erinnerung an das System “in Auftrag gegeben” und/oder wieder gelöscht.
  3. ErinnerungsReceiver: Dies ist der BroadcastReceiver, der vom System benachrichtigt wird, wenn es wieder Zeit für die nächste Erinnerung ist. Das ist quasi das Gegenstück zu unserem ErinnerungsVerwalter
  4. WearSchnittstelle: Diese Klasse empfängt Nachrichten, die die Uhr über die MessagingAPI schickt. Dies geschieht in unserem Fall im wear Modul, wenn man in der Wear-App die Erinnerung de-/aktiviert.

Das mobile-Modul enthält WearActivity als einzige Java-Klasse. Dies ist die Activity, die auf der Smartwatch geladen wird, wenn unsere App gestartet ist.

An der Anzahl der Klassen in den zwei Modulen merkt ihr schon, dass auf der Uhren-Seite weniger gemacht zu werden scheint – so ist es auch, wir nutzen die Uhr als Ein-/Ausgabe und geben die dadurch erhaltenen Informationen immer an das Handy weiter, welches diese dann verarbeitet.

 

1. Das Layout der Einstellungs App

Zunächst erstellen wir das Layout der Einstellungs-Activity, welche wir benötigen um unsere App zu de-/aktivieren und einzustellen, wie häufig die App uns an die Uhrzeit erinnern soll. Das Layout speichern wir in der Datei res/layout/activity_einstellungen.xml (im mobile Modul des Projekts). Enthalten ist in dem Layout primär ein Switch, welcher verwendet wird um zu visualisieren ob die komplette App aktiviert oder deaktiviert ist.

Gewrapt wird der Switch in ein RelativeLayout. In diesem kann man Elemente relativ zu dem übergeordneten Layout und anderen Komponenten positionieren, was für unseren Anwendungsfall das einfachste ist.

Ihr könnt übrigens in AndroidStudio die Geräte ändern, in der euer Layout grafisch dargestellt wird (auch runde/eckige Smartwatches – hier zwar nicht sinnvoll, aber grundsätzlich sehr cool).

Die Einstellungen zur Activity. Die Vorschau in Android Studio ist immer mit etwas Vorsicht zu genießen.
Die Einstellungen zur Activity. Die Vorschau in Android Studio ist immer mit etwas Vorsicht zu genießen.

In dem Screenshot sieht man aber auch schon, dass der Grafik-Renderer von Studio mit Vorsicht zu genießen ist – denn dieser seltsame Schwarz-Weiße Switch, sieht in der Realität natürlich so aus, wie wir ihn erwarten.

Activity: Eine Activity ist eine Java-Klasse, die “etwas anzeigt”. Man kann in ihr Elemente anzeigen lassen und mit ihnen interagieren. Jede App hat mindestens eine Activity. Für die Entwicklung von Android Apps ist es notwendig, zu verstehen, dass eine Activity verschiedene Stati (Sprich “wird gestartet”,”läuft”, …) haben kann – Infos dazu im Activity Life Cycle.

Unsere Views bekommen jetzt noch aussagekräftige ID’s und ein paar Eigenschaften für ihre Optik und Positionierung zugewiesen. Mit den ID’s können wir gleich in unsere Activity auf den Switch ‘zugreifen’, bzw. das richtige Element wiederfinden.

View: Eine View ist eine graphische Komponente, die Informationen bieten kann oder der Interaktion dient. Sprich Buttons, TextLabels oder wie bei uns oben der Switch.

Und schon steht unser grobes Layout! Gehen wir über zu dem Code der Activity.

2. Die Einstellungs Activity (Smartphone)

In der Datei EinstellungsActivity.java (zu finden im src/ Ordner hinter dem Packagenamen de.mammuth.timereminder) können wir jetzt die Logik der Einstellungs-Ansicht programmieren.

Das sieht doch schon mal besser aus als im Emulator….

Gemäß des Activity-Lifecycles wird beim Start der App onCreate() aufgerufen. Hier setzen wir dann in Zeile 34 mit setContentView() das oben erstellte Layout. Danach initalisieren wir unseren Switch, sodass wir dann in Zeile 54ff einenonCheckedChangeListener() auf ihn registrieren können. Listener sind ein sehr wichtiges Konstrukt, welches dir erlaubt Event-basiert zu programmieren und auf gewisse Sachen zu reagieren. Als Resultat wird der Code in onCheckedChanged()aufgerufen, sobald wir den Switch betätigen. In dieser Methode erledigen wir dann die Aufgaben: Änderungen bzw. Status des Switches abspeichern, dementsprechend die Erinnerung de-/aktivieren.

In der onCreate() passieren noch zwei andere Dinge: Zum einen initialisieren und verbinden wir den GoogleApiClient. Über den ApiClient können wir auf die DataAPI zugreifen, die wir für das Synchronisieren der Einstellungen (“Sind Benachrichtigungen de-/aktiviert?”) mit der Wear benötigen. Wir holen uns explizit nur die Wear-Api mit addApi(Wearable.API) (und nicht etwa noch G+, Drive, Bewegungs-Erkennung, …). Des Weiteren initialisieren wir in Zeile 50 ein Objekt der Klasse ErinnerungsVerwalter. Diese Klasse schauen wir uns im nächsten Schritt genauer an.

Um die Einstellungen zu Speichern, oder bei einem Switch-Druck den neuen Status zu vermerken, haben wir zwei extra Methoden, getEinstellungen() und schreibeEinstellungen(boolean enabled). Hier werden die Schnittstellen der DataApi genutzt um die Einstellung zu speichern und zu synchorniseren.

Wichtige Klassen
DataApiDie DataApi (auch Wearable Data Layer API) gehört zu den Google Play Services und bietet Schnittstellen an, um Smartphones mit Smartwatches zu synchronisieren. Man kann Daten abspeichern, die alle Geräte abrufen können, oder auch Messages zu den Geräten schicken, die diese dann annehmen und verarbeiten können. Quelle und weitere Infos: developer.google.com
AlarmManagerGehört zum Android Framework und gibt Entwicklern die Möglichkeit zeit-abhängig Aktionen auszuführen. Sprich man muss nicht einen Hintergrundservice bauen, der selbst die Uhrzeit zählt, um dann alle 15 Minuten eine Aktion, wie das Laden einer Datei aus dem Internet, ausführt (Prinzip des busy-waitings) sondern man kann sagen “hey Android, sag mir bitte in 15 Minuten bescheid, ich hab da was zu tun”. Das ist ressource-schonend und sollte immer gemacht werden, sobald man etwas zu a) bestimmten Zeiten oder b) in festen Intervallen wiederkehrend machen möchte! Quelle und weitere Infos: developer.google.com

3. ErinnerungVerwalter Klasse

In der EinstellungsActivity initalisieren wir zum Start der App einen ErinnerungVerwalter. In dieser Klasse geben wir mit den Methoden setzeErinnerung() und entferneErinnerung() einen Weckzustand an Androids AlarmManager, oder löschen eben bisherige Alarms.

Dazu deklarieren im Konstruktor in Zeile 33ff eine Instanz des AlarmManagers und sagen ihm, dass die Klasse ErinnerungReceiver aufgerufen werden soll, wenn Android unsere App zu der gewünschten Uhrzeit weckt. “In Auftrag” gegeben wird der Alarm in Zeile 60 am Ende der Methode setzeErinnerung().

Denn zuvor müssen wir ja erst einmal herausfinden, wann der nächste Alarm überhaupt ist. Dafür haben wir die Methode getErstenAlarm(), die uns ein Date-Objekt zurückliefert. Hier nehmen wir einfach die aktuelle Uhrzeit, setzen die Minuten auf 00 und erhöhen die Stundenanzahl um eins. Somit haben wir einen Alarm zur nächsten vollen Stunde.

Bei so einer App ist es naheliegend, eine Erweiterung einzubauen, sodass man nicht nur alle volle Stunde, sondern vielleicht auch alle 30 Minuten oder 2 Stunden erinnert wird. Dies habe ich ursprünglich in dergetErstenAlarm() berücksichtigt – die Unterscheidung in entsprechender Methode ist noch auskommentiert enthalten und vielleicht ganz interessant.

4. ErinnerungReceiver

Diese Klasse ErinnerungReceiver ist ein sog. BroadcastReceiver – in ihr wird der “Weckruf” von Androids AlarmManager empfangen und verarbeitet, den wir im ErinnerungVerwalter aufgegeben haben. In unserem Fall soll hier eine Notification erstellt werden und auf allen Geräten angezeigt werden.

Fast wie eine Uhr :-) Zur richtigen Zeit die richtige Information auf dem Display
Fast wie eine Uhr :-) Zur richtigen Zeit die richtige Information auf dem Display

Um dies zu erreichen, haben wir eine Methode sendeBenachrichtigung(), welche in der onReceive() aufgerufen wird. onReceive() selbst wird, wie der Name bereits sagt, aufgerufen sobald der AlarmManager unsere App weckt. Zunächst erstellen wir uns in Zeile 41einSimpleDateFormat mit der Form HH:mm (zB. 15:03 Uhr) und parsen damit den aktuellen Zeitpunkt als String: String time = sdf.format(new Date());

In Zeile 46f definieren wir, was geschehen soll, wenn der Nutzer auf unsere Notification klickt – nämlich die EinstellungsApp öffnen.

Mit Android 5 hat Google auch einen neuen NotificationBuilder eingeführt, welcher auch um die Funktionalität der Notifiactions auf Wearables erweitert wurde: NotificationCompat.Builder. Mit diesem bauen wir uns in Zeile 54ff die Notification, setzen das Icon, den Titel und die Beschreibung, wobei in die Beschreibung unsere oben abgefragte aktuelle Uhrzeit eingebaut wird (Zeile 58). Mit .setDefaults(NotificationCompat.DEFAULT_ALL) bestimmen wir noch, dass diese Notification auf jeden Fall auf allen Geräten angezeigt werden soll, also auch unserer Smartwatch. Mit setContentIntent() fügen wir hinzu, was bei Klick passieren soll und zu guter letzt haben wir noch ein Vibrations-Muster definiert, welches wir der Benachrichtigung anhängen.

Das VibrationPattern funktionert so, dass es immer abwechselnd die Zeit in Millisekunden angibt, die gewartet und dann vibriert werden soll. Bei uns also 0ms warten (zu Beginn), 200ms vibrieren, 100ms warten, 200ms vibrieren, … Hier gibt es noch einiges an Spielraum, wo ihr euch selbst austesten könnt. So könnte man zum Beispiel ein großes Hintergrundbild setzen, ein Expanded Layout erstellen, oder weitere Actions hinzufügen. Probiert es aus!

Die Receiver Klasse muss im Android Manifest als solche gekennzeichnet sein: <receiverandroid:name=de.mammuth.timereminder.ErinnerungReceiver/>

5. WearSchnittstelle

Die WearSchnittstelle Klasse empfängt Nachrichten, die die Uhr über die Messaging API (gehört zur DataApi) schickt. Dies geschieht in unserem Fall in der WearActivity (im Wear-Modul), wenn man in der App die Erinnerung aktiviert oder deaktiviert.

Diese brauchen wir, weil der Nutzer über die Uhr ja die Erinnerung de-/aktivieren kann. Hierzu ist es natürlich notwendig, dass wir in Echtzeit von der Uhr erfahren, wenn der Nutzer diese Einstellung ändert. Wie die Uhr diese Benachrichtigungen schickt, sehen wir im nächsten Abschnitt in der WearActivity. Wenn die Message reinkommt, wird die Methode onMessageReceived() in der Klasse WearSchnittstelle aufgerufen. Diese ist ein WearableListenerService und wird in Zeile 24ff des Manifests auch als solcher gekennzeichnet.

Die Schnittstelle zur Uhr ist der zentrale Part des Projekts.

 

Als erstes initialisieren wir uns eine Instanz des ErinnerungVerwalters – über den können wir schließlich die zukünftigen Erinnerungen beenden oder in Auftrag geben. In dem Switch-Case Konstrukt in Zeile 28ff finden wir heraus, welche Nachricht uns die Uhr geschickt hat (starten oder entfernen). Je nachdem benutzen wir dann die Methoden des ErinnerungVerwalters um den Alarm zu setzen oder zu entfernen: erinnerung.setzeErinnerung(); oder erinnerung.entferneErinnerung();

Auch posten wir eine Meldung auf das Handy, dass die Erinnerung de-/aktiviert wurde: Toast.makeText(this, Erinnerung aktiviert, Toast.LENGTH_SHORT).show();

Die schreibeEinstellungen() Methode ist wieder die gleich, die wir bereits kennen. Sie nutzt den GoogleApiClient um den Status der App mit der DataApi zu speichern, sodass die Einstellung zwischen Smartphone und Uhr synchronisiert sind.

Fortsetzung folgt…

Im zweiten Teil unseres Workshops zeigen wir dir dann, wie der Wearable-Teil der App aussieht, wie du die App auf dem Handy und der Uhr zum Laufen bringst und welche weiteren Möglichkeiten das Grundgerüst der App durch Weiterentwicklung noch bietet. Teil 2 dieses Workshops findest du hier auf der Android-User-Homepage (0,79 Euro) und im Juni in Ausgabe 07 von Android Power User.

 

Danke, dass du diesen Artikel gekauft hast! Falls du beim Nachprogrammieren auf Probleme stoßen solltest, erreichst du die Redaktion per Mail an redaktion@android-user.de. Bitte in der E-Mail als Betreff den Support-Code: 72433 angeben.

Kommentiere den Artikel

Please enter your comment!
Please enter your name here