Die Android Developer Roadmap

Wie oft wurde ich schon gefragt, was muss ich machen, um Android Entwickler zu werden? Eine Frage, die scheinbar noch immer viele Leute interessiert, auch wenn so langsam die Goldgräber-Stimmung wieder abflaut. Um die Frage umfänglich zu beantworten reichen 2-3 Sätze einfach nicht, daher habe ich einfach mal eine Reihe von Themen zusammengestellt, die für einen Android Entwickler relevant sind – nur um mal einen groben Überblick zu bekommen.

Programmiersprache

Die Programmiersprachen in denen Native Android Apps üblicherweise entwickelt werden sind Java und Kotlin. Java ist eine von Sun entwickelte Programmiersprache, die intuitiv zu lernen und zu verstehen ist. Kotlin ist eine recht neue Programmiersprache, die viel Ähnlichkeit mit Java hat und seit ein paar Jahren von Google zur Entwicklung von Android Apps eingeführt wurde. Der Kotlin Code wird, genau wie der Java Code, vom Compiler in den Bytecode übersetz, der von der Android VM ausgeführt werden kann. Darüber hinaus wird auch die Programmiersprache Dart mit dem Flutter Framework immer wichtiger, aber dieses spezielle Thema lasse ich hier einfach mal weg, um es nicht noch komplizierter zu machen. Anfängern, die noch keine Programmierkenntnisse haben, empfehle ich auf jeden Fall die Programmiersprache Java, da mit der Programmiersprache noch viel mehr möglich ist, als nur Android Apps zu programmieren auch wenn Google/Alphabet selbst hier wohl eher Kotlin empfiehlt.

IDE

Die IDE (Entwicklungumgebung) eines Android Entwicklers ist Android Studio. Android Studio basiert auf Intellij von Jetbrains und kann fertig vorkonfiguriert kostenlos auf der Android Entwickler Webseite heruntergeladen werden. Android Studio ist kostenlos für alle gängigen Betriebssysteme wie Windows, Linux und MacOS verfügbar

Neben dem Code-Editor, dem Compiler und dem Emulator stehen in Android Studio noch eine Reihe anderer Tools zur Verfügung, die dem Android Entwickler das Leben leichter machen. Z.B. Debugger, Android-Debug-Bridge, CPU-Profiler, Layout-Inspector, GIT Versionsverwaltung und Layout-Designer, um nur einige zu nennen. Es gibt zwar auch die Möglichkeit, mit Visual Studio Code oder sogar mit dem vim zu arbeiten, aber man sollte schon einen sehr guten Grund dafür haben, nicht mit Android Studio zu arbeiten.

Dateiformate

Die wichtigsten Dateiformate für einen Android Entwickler sind auf jeden Fall „.java“ und „.xml“. Die „.java“ Dateien enthalten den programmierten Sourcecode und die XML Dateien können Layouts, Manifest, Texte, Drawables, Dimensionen, Styles und vieles mehr enthalten. Beide Dateitypen sind Textdateien, die mit jedem verfügbaren Texteditor bearbeitet werden können. Neben den beiden wichtigen Dateiformaten gibt es noch vieles mehr (Z.B. Fonts, Bilder, Gradle Scripts, Properties-Files, etc.) auf all diese Fileformate werde ich hier aber nicht weiter eingehen. Allerdings möchte ich hier noch erwähnen, dass Icons und Bilder üblicherweise im JPG oder PNG Format abgelegt werden und dass Dateien im Resources Folder kein „-“ Zeichen enthalten dürfen.

Das Android-Manifest

Die AndroidManifest.xml Datei benötigt jedes Android Studio Projekt. Die Datei befindet sich unter app/src/main/AndroidManifest.xml. Sie enthält die Liste der Berechtigungen, die von der App benötigt werden, sowie alle Activities, Broadcast-Receiver und Services. Zusätzlich findet man hier auch den App-Name, das App-Icon, verwendete Styles, Themes, Ausrichtungen (Landscape/Portrait) und vieles mehr. Die AndroidManifest.xml Datei ist der Dreh und Angelpunkt eines jeden Android Projektes und darf nicht vernachlässigt werden.

Android Emulator

Android Studio enthält eine Emulator Integration mir der Apps ohne physisches Gerät entwickelt und getestet werden können. Im AVD Manager (Android Virtual Device Manager) können beliebige virtuelle Geräte erstellt und verwaltet werden. Startet man eine Android App im Debug-Mode auf einem virtuellen Gerät wird dieses genau wie ein physisches Gerät über die ADB (Android Debug Bridge) angebunden.

ADB (Android Debug Bridge)

Über die Android Debug Bridge erfolgt die Kommunikation zwischen einem Android Gerät und dem Computer. Über ADB können Apps installiert werden, Logcat Ausgaben ausgelesen werden. Weiterhin hat man die Möglichkeit, eine Unix-Shell auf dem Android-Gerät zu öffnen, über die man Zugriff auf eine Reihe von Command-Line-Tools auf dem Android-Gerät erhält.

Um eine Verbindung über ADB mit dem Gerät aufbauen zu können, muss in den Entwickler-Einstellungen die Funktion USB-Debugging aktiviert sein.

Zusätzlich zur Nutzung von ADB über USB gibt es auch die Möglichkeit einer WiFi (WLAN) Verbindung. Details zur Nutzung von ADB über WLAN können unter

https://developer.android.com/tools/help/adb.html nachgelesen werden.

Entwickleroptionen

Die Android-Entwickleroptionen sind auf allen Geräten ab Android 4.2 versteckt und müssen erst sichtbar gemacht werden. Dazu öffnet man die Einstellungen und wählt den Menüpunkt Über dieses Telefon. Dieser Info-Screen enthält die Build-Nummer. Klickt man die Build-Nummer 7-mal an, sind die Entwickleroptionen sichtbar.

Die Entwickleroptionen enthalten eine sehr umfangreiche Liste von Einstellungen, mit denen das Entwickeln oder Testen einer App vereinfacht wird.

Einige wertvolle Entwickleroptionen sind unter andern:

  • Aktiv lassen
    Display wird beim Laden nicht in den Ruhezustand versetzt
  • Demomodus der System-UI
    Versetzt die Statusbar in den Demo-Mode. Keine Benachrichtigungen, Feste Uhrzeit, WLAN, LTE und voller Akku werden angezeigt
  • Simulierte Standorte
    Für GPS basierte Apps sehr nützlich.
  • Fingertipps anzeigen
    Visuelles Feedback für Fingertipps anzeigen
  • Zeigerposition
  • Zeigt ein Overlay mit einem Fadenkreuz und Daten zu den Tippaktivitäten auf dem Display
  • Layoutgrenzen einblenden
    Zeigt Größe, Margin und Padding aller verwendeten Views auf dem Screen. Sehr wertvoll bei Schwierigkeiten mit dem Layout
  • Farbraum simulieren

Hier kann eine Fehlsichtigkeit wie Farbenblindheit, Rot-Grün Sehschwäche oder Blau-Gelb Sehschwäche simuliert werden.

Android Logcat

Im Android Logcat finden sich alle Log-Ausgaben, die mit den Methoden der android.util.Log Klasse geschrieben wurden. Die Logcat Ausgaben können mit „adb logcat“ abgerufen werden. Es gibt aber auch eine Integration in das Android Studio, so dass man adb nicht auf der Konsole benutzen muss.

Im Logcat werden auch die Stack-Traces von unbehandelten Exceptions und System-Messages angezeigt. Um von der Flut an Informationen nicht erschlagen zu werden kann man die Logcat Ausgeben filtern. Möglich ist es einen einzelnen Prozess zu filtern, nur einen bestimmten Loglevel (VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT) oder mit einem Regulären-Ausdruck zu filtern.

Activity

Die wichtigste aller Komponenten in einer Android App ist (fast) immer die Activity. Eine Activity zeigt eine View auf dem Screen und interagiert mit dem User. Um zwischen Activities zu navigieren kann die Methode startActivity oder startActivityForResult genutzt werden. Eine Activity hat einen Lifecycle, der mit der onCreate Methode anfängt und mit der onDestroy Methode endet. Details zum Lifcycle einer Activity können unter https://developer.android.com/guide/components/activities/activity-lifecycle nachgelesen werden. Jede Activity muss in der AndroidManifest.xml Datei eingetragen werden. Fehlt der Eintrag im AndroidManifest, wird der Aufruf der Methode startActivity oder startActivityForResult fehlschlagen. In modernen Anwendungen wird statt „extends Activity“ eher „extends AppCompatActivity“ verwendet. Diese Klasse ist Teil des android.support.v7.app Packages das in com.android.support:appcompat-v7 enthalten ist. Diese AppCompatActivity enthält einiges an Boilerplate Code, den man nicht jedes Mal selber implementieren möchte und in vielen Situationen die Arbeit deutlich erleichtert.

Service

Ein Service ist eine Komponente, die für eine langlaufende Operation im Hintergrund ohne Interaktion mit dem Nutzer verwendet wird. Jeder Service muss, genau wie eine Activity, im AndroidManifest eingetragen werden, um aufgerufen werden zu können. Der Start eines Services erfolgt entweder mit der Methode startService() oder bindService(). Die bindService() Methode wird verwendet, wenn man sich über das Client-Service Interface der Service-Implementierung an den Service binden möchte um schnell und einfach Daten auszutauschen. Darüber hinaus können Services auch genutzt werden, um Dienste für andere Apps bereitzustellen oder sogenannte Floating Windows anzuzeigen.

BroadcastReceiver

Android Apps können Broadcast-Nachrichten mit anderen Apps und dem Android System austauschen. Das Android System sendet für verschiedene System-Events Broadcast Messages aus, die man in der App mit einem BroadcastReceiver empfangen kann. Z.B. beim Booten, oder wenn ein Ladegerät angesteckt wird. Apps können selbst auch Broadcast Nachrichten schicken, die dann von anderen Apps oder anderen Komponenten der gleichen App empfangen werden können. So kann z.B. die Kommunikation zwischen einer Activity und einem Service innerhalb einer App realisiert werden.

Um Broadcast Nachrichten eines bestimmten Typs zu empfangen, muss man sich für den Nachrichtentyp registrieren. Dies erfolgt entweder statisch im AndroidManifest oder dynamisch innerhalb der App mit einem IntentFilter.

Um eine Broadcast Nachricht zu schicken, wird die sendBroadcast(Intent) Methode verwendet. Ausführliche Infos zum BroadcastReceiver und zum Senden und Empfangen von Nachrichten können unter https://developer.android.com/guide/components/broadcasts.html nachgelesen werden.

Intent

Bei einem Intent handelt es sich um ein spezielles Datenobjekt, dass zum Austausch von Informationen zwischen Komponenten und Apps verwendet wird. Im Wesentlichen werden Intents für die folgenden 4 Use-Cases verwendet.

  1. Starten einer Activity
    Eine Activity repräsentiert einen Screen einer App. Das Starten einer Activity erfolgt immer mit Hilfe eines Intents.
  2. Rückgabewerte aus einer Activity empfangen
    Wird eine Activity mit startActivityForResult gestartet, kann man beim Rücksprung von dem Screen auf den aufrufenden Screen einen oder mehrere Rückgabewerte empfangen, die in einem Intent an die aufrufende Activity zurückgegeben werden.
  3. Starten eines Service
    Um einen Service zu starten ist es erforderlich die Methode startService(Intent) aufzurufen. Der hier übergebene Intent enthält die Beschreibung des Service und kann zusätzliche Informationen enthalten, die der Service benötigt.
  4. Zustellung einer Broadcast-Nachricht
    Es ist möglich mit Hilfe der sendBroadcast() Methode Nachrichten an andere Apps oder andere Komponenten der eigenen App zu senden. Sowohl der Nachrichtentyp als auch die Daten der Nachricht werden in einem Intent verpackt um ein einheitliches Interface nutzen.

Ausführliche Infos zur Intent Klasse sind unter https://developer.android.com/guide/topics/intents/intents-filters.html zu finden.

Handler

Ein Handler ermöglicht es, Messages und Runnables über eine MessageQueue eines Threads zu senden und zu verarbeiten. Jeder Handler ist über eine MessageQueue mit einem Thread verbunden. Um einen Handler für eine Activity zu instanziieren kann man einfach folgende Zeile aufrufen.

Handler handler = new Handler(Looper.getMainLooper());

Es gibt 2 wesentliche Einsatzzwecke für einen Handler.

  1. Das Senden von Messages und ausführen von Runnables zu einem festgelegten Zeitpunkt in der Zukunft
  2. Das Senden von Messages und ausführen von Runnables von einem anderen Thread.

Die Methoden zum Ausführen von Runnables sind:

  • post(Runnable)
  • postAtTime(Runnable, long)
  • postDelayed(Runnable, Object, long)

Die Methoden zum Senden von Messages sind:

  • sendEmptyMessage(int)
  • sendMessage(Message)
  • sendMessageAtTime(Message, long)
  • sendMessageDelayed(Message, long)

AsyncTask

Einen AsyncTask verwendet man, um eine blockierende Operation auf einem separaten Worker-Thread auszuführen. Mit Hilfe einer AsyncTask Implementierung wird der blockierende Teil der Operation asynchron in einem Worker-Thread ausgeführt, um das User-Interface nicht unnötig zu blockieren. Nach der Ausführung der blockierenden Operation wird das Ergebnis dann wieder an den UI-Thread zurückgegeben ohne dass man sich selbst um das Management der Threads kümmern muss. Um einen AsyncTask zu nutzen muss man eine Klasse erstellen, die von AsyncTask erbt und die folgenden Methoden überschreiben.

  • doInBackground()
  • onPostExecute()

Weitere Details zum Einsatz von AsyncTask findet man auf der offiziellen Android-Entwickler-Seite unter https://developer.android.com/reference/android/os/AsyncTask.html

View

Jedes User-Interface setzt sich aus einer Reihe von Views zusammen, die alle direkt oder Indirekt von der View Klasse abgeleitet sind. Jeder View belegt ein vorgegebenes Rechteck auf dem Screen und ist dann in diesen Bereich für das Zeichnen der Komponenten und das Eventhandling verantwortlich. Views können einander überlappen und auch komplett abdecken. Neben den im Android-SDK enthaltenen Views wie z.B. TextView, ImageView, Button, ImageButton. CheckBox, WebView, VideoView, SeekBar, ProgressBar, MapView, ListView, RecyclerView, etc. gibt es auch noch endlos viele Views, die von Entwicklern erstellt und in vielen Fällen unter einer OpenSource Lizenz (z.B. MIT, Apache, GPL, etc.) veröffentlicht wurden. Ein sehr guter Einstieg ist z.B. https://android-arsenal.com/. Hier findet man sehr View Implementierungen und andere Android Bibliotheken in einem gut sortierten Katalog.

Die Screens einer Android App werden (meistens) in Layout-XML Files definiert, die dann die Views enthalten. Android Studio enthält einen sehr guten Layout-Designer, mit dem es möglich ist, die Layouts grafisch zusammenzustellen, ohne dass man eine Zeile Code programmieren muss. In der onCreate Methode der entsprechenden Activity kann man dann einfach den Screen mit Hilfe der Funktion setContentView(R.layout.meinlayout) anzeigen.

Layouts

Layouts werden verwendet, um Views auf dem Bildschirm zu organisieren und zu positionieren. Aus Sicht einer Android App sind Layouts nichts anderes als Views, die andere Views als Child-Views enthalten. Layout-Klassen erben direkt oder indirekt von der Klasse ViewGroup, die als Basisklasse für Layouts und Container dient. Die am meisten verwendeten Layouts sind wohl:

  • LinearLayout
    Das LinearLayout ist sehr gut geeignet, um Views und ViewGroups horizontal oder vertikal auszurichten. Das Layout ist sehr einfach zu verwenden und besonders für einfache Layouts zu empfehlen.
  • FrameLayout
    Das FrameLayout ist dafür vorgesehen, um einen vorgegebenen Bereich zu blockieren, um dann ein einzelnes Element darin zu verwenden. Ich persönlich nutze es gerne, um Elemente auf einfache Art und Weise auszutauschen, ohne mir darum Gedanken machen zu müssen, ob sich ein Layout dadurch verändert oder nicht. Um die Position innerhalb eines FrameLayouts zu positionieren kann das XML Attribut android:layout_gravity verwendet werden.
    Mögliche Werte sind hier:
    • left
    • right
    • center
    • top
    • bottom
    • center_horizontal
    • center_vertical

      Views innerhalb vom FrameLayout können einander überlappen und auch komplett abdecken. Aus Performance Gründen sollte aber immer versucht werden, Overdraw zu vermeiden.
  • GridLayout
    Hierbei handelt es sich um ein Layout, das alle enthaltenen Elemente in einem 2 dimensionalen Raster organisiert. Mit den Attributen android:rowCount und android:columnCount kann die Anzahl der Zeilen und Spalten festgelegt werden.
  • RelativeLayout
    Ein Layout bei dem die Position der enthaltenen Views in Relation zu einander angeordnet werden können.
    Einige der verfügbaren Attribute, die dazu verwendet werden können, um Views innerhalb eines RelativLayout zu organisieren sind:
    • android:layout_alignParentTop
    • android:layout_centerVertical
    • android:layout_below
    • android:layout_toRightOf
    • android:layout_toLeftOf
  • ConstraintLayout
    Bei dem ConstraintLayout handelt es sich um eine Erweiterung, die in der Support-Library enthalten ist. Das Layout ist sehr gut für die Nutzung in komplexen Layouts geeignet und bietet eine sehr gute Performance, ohne die Notwendigkeit mehrere Layouts ineinander verschachteln zu müssen. Die Möglichkeiten, das Layout zu gestalten ist hier sehr umfangreich und daher beschränke ich mich hier darauf, auf die offizielle Doku unter https://developer.android.com/reference/android/support/constraint/ConstraintLayout.html zu verweisen.
  • MotionLayout
    Das MotionLayout ist ein ConstraintLayout mit dem es möglich ist, Animationen von einem Zustand des Layouts zu einem anderen Zustand zu realisieren. Das MotionLayout macht komplexe Transitionen von einem Zustand der enthaltenen Views zu einem anderen möglich, ohne die hierfür benötigten Animationen in Java realisieren zu müssen. In den meisten Fällen können auch komplexe MotionLayouts einfach in XML umgesetzt werden.

Alle Layouts können ineinander verschachtelt werden. Dies ist bei komplexen Layouts gelegentlich nötig, sollte aber unter Verwendung der ConstraintLayout-Klasse nach Möglichkeit immer vermieden werden, um eine möglichst gute Performance zu gewährleisten.

Alle Screens, die via XML Datei vorliegen, sind im Ordner res/layout abgelegt. Wie bei allen anderen Ressource-Dateien ist es auch hier möglich, mit Hilfe eines Qualifiers ein alternatives Layout für eine spezifische Sprache, Ausrichtung, Display-Größe, etc. zu laden. Alle Details dazu findet man unter https://developer.android.com/guide/topics/resources/index.html.

Animations

Viele Android Apps nutzen Animationen, um die User-Experience zu verbessern. Zur einfachen Umsetzung von Animationen gibt es in Android eine Unmenge An Möglichkeiten die alle ihre Vor- und Nachteile haben. Laut der Android Guidelines ist es immer wichtig darauf zu achten, dass die Animationen „meaningfull“ sind (Eine Bedeutung haben).

Vorhandene Animationen sind:

  • AlphaAnimation
  • RotateAnimation
  • ScaleAnimation
  • TranslateAnimation

Es ist aber auch möglich beliebige Animationen selber zu implementieren. Als Basis für eine eigene Animation sollte immer die abstrakte Klasse Animation verwendet werden.

Einer Animation kann man einen AnimationListener übergeben. Mit seiner Hilfe kann auf die Events AnimationStart, AnimationEnd, AnimationRepeat reagiert werden. Animationen können alternativ auch als XML Ressource-Dateien angelegt werden und mit den AnimationUtils geladen werden.

Da Animationen nicht immer linear verlaufen sollen, kann man einer Animation auch einen Interpolator mitgeben. Mit seiner Hilfe ist es möglich, die Animation in einen Kurvenverlauf ablaufen zu lassen.

Toast

Ein Toast dient dazu, kurze Nachrichten auf dem Bildschirm anzuzeigen. In den meisten Fällen werden diese am unteren Rand in einem kleinen Fenster angezeigt, dass nach wenigen Sekunden wieder von alleine verschwindet. Es ist aber auch möglich einen Toast oben oder mittig anzuzeigen und ihm ein eigenes Layout zu verpassen. Mehr Infos zum Toast findet man unter https://developer.android.com/guide/topics/ui/notifiers/toasts.

Snackbar

Die Snackbar bietet eine einfache Möglichkeit, eine kurze Info am unteren Rand des Displays anzuzeigen. Die Snackbar verschwindet mach an paar Sekunden wieder. Eine Snackbar kann auch interaktive Elemente enthalten, wie z.B. den „Rückgängig machen“ Button nach dem Löschen einer Mail in der Google-Mail App.

Dialog

Dialoge sind kleine Fenster, die den Bildschirm nicht füllen. Dialoge werden oft verwendet, wenn eine Eingabe benötigt wird, bevor fortgefahren werden kann. Dialoge können Texte, Eingabefelder, Listen, Buttons, oder andere Views enthalten. Auch komplexe XML Layouts können in einem Dialog verwendet werden. In vielen Fällen reicht es, einen einfachen AlertDialog mit dem AlertDialog.Builder zu erzeugen. Ein AlertDialog besteht aus einem Titel, einem Inhalt und bis zu drei Buttons. Zwei weitere existierende Dialog-Typen sind DatePickerDialog und TimePickerDialog, die ebenfalls mit dem Builder erzeugt und angezeigt werden können.

Notifications

Notifications werden dazu verwendet, um den Nutzer über Ereignisse in einer App zu informieren. Diese Notifications werden dann außerhalb der eigentlichen App in der Notification-Liste dargestellt. Notifications sind auch sichtbar, wenn die App gerade nicht genutzt wird. Da sich im Laufe der Zeit über die vielen Android Versionen hinweg sehr viel am Code zum Erstellen von Notifications geändert hat ist es zu empfehlen, Notifications mit der NotificationCompat-Klasse in der com.android.support:support-compat  Library zu erstellen. Details zu Notifications und NotificationCompat können unter https://developer.android.com/training/notify-user/build-notification.html nachgelesen werden.

SharedPreferences

Zum Speichern kleiner Datenmengen, die keine komplexe Struktur besitzen, kann man SharedPreferences verwenden. Die SharedPreferences API ermöglicht es, beliebige Key Value Paare persistent innerhalb der App zu speichern und zu lesen. Mit der SharedPreferences API können alle primitiven Datentypen (boolean, float, int, long, Strings) persistent gespeichert werden. Die Key Value Paare werden dann im XML Dateien gespeichert, die auch nach dem beenden der App gespeichert bleiben. SharedPreferences eignen sich z.B. sehr gut, um die Konfiguration zu speichern ohne dass man gleich eine Datenbank zum Speichern der Daten einsetzen muss. Weitere Infos zu SharedPreferences sind unter https://developer.android.com/training/data-storage/shared-preferences.html zu finden.

SQLite

Mit Hilfe von SQLite können in einer Android App strukturierte Daten abgelegt werden. SQLite ist eine relationale Datenbank, die in allen Android basierten Geräten verfügbar ist. Die Datenbank verfügt über eine SQL-92 Query Language und mit ihr ist es möglich, größere Datenmengen (Im Vergleich zu SharedPreferences) zu speichern und zu verarbeiten. Statt die SQLite API zu verwenden, kann man auch „Room“ nutzen. Bei Room handelt es sich um einen OR-Mapper, der ähnlich wie Hibernate das Mapping zwischen den Objekten und der Relationalen Datenstruktur übernimmt. Room ist speziell für die Nutzung mit einer SQLite Datenbank unter Android entwickelt und mit Hilfe der Annotations ist es möglich, sehr schnell und einfach eine SQLite Datenbank in eine App zu integrieren.

Sonstiges

Neben den oben angesprochenen Themen gibt es noch eine Vielzahl anderer APIs und Themen, die oft in Android Apps zum Einsatz kommen, auf die ich hier aber nicht im eingehen werde. Z.B. JobScheduler, Bluetooth, NFC, Firebase, WiFi, Wear-OS, Android-Auto, Android-Things, Instant-Apps, Content-Provider, Kamera, Sensoren, Google Play Store, Proguard, JSON, Gradle, etc.

Fazit

Alles in allem ist der Einstieg in die Android Programmierung (etwas) mehr als nur Java und XML. Es gibt eine sehr viele APIs, Werkzeuge und Konzepte, die man kennen sollte, bevor man professionell Android Apps entwickelt. Es lohnt sich aber, sich mit diesen Themen zu beschäftigen und Apps zu realisieren, die einfach Spaß machen.