Rheinwerk Computing < openbook >

 
Inhaltsverzeichnis
Vorwort
Teil I Grundlagen
1 Android – eine offene, mobile Plattform
2 Hallo Android!
3 Von der Idee zur Veröffentlichung
Teil II Elementare Anwendungsbausteine
4 Wichtige Grundbausteine von Apps
5 Benutzeroberflächen
6 Multitasking
Teil III Gerätefunktionen nutzen
7 Telefonieren und surfen
8 Sensoren, GPS und Bluetooth
Teil IV Dateien und Datenbanken
9 Dateien lesen, schreiben und drucken
10 Datenbanken
Teil V Multimedia und Produktivität
11 Multimedia
12 Kontakte und Organizer
A Einführung in Kotlin
B Jetpack Compose
C Häufig benötigte Codebausteine
D Literaturverzeichnis
E Die Begleitmaterialien
Stichwortverzeichnis

Ihre Meinung?
Spacer
<< zurück
Android 11 von Thomas Künneth
Das Praxisbuch für App-Entwickler
Buch: Android 11

Android 11
Pfeil 3 Von der Idee zur Veröffentlichung
Pfeil 3.1 Konzept und Realisierung
Pfeil 3.1.1 Konzeption
Pfeil 3.1.2 Fachlogik
Pfeil 3.1.3 Benutzeroberfläche
Pfeil 3.2 Vom Programm zum Produkt
Pfeil 3.2.1 Protokollierung
Pfeil 3.2.2 Fehler suchen und finden
Pfeil 3.2.3 Debuggen auf echter Hardware
Pfeil 3.3 Anwendungen verteilen
Pfeil 3.3.1 Die App vorbereiten
Pfeil 3.3.2 Apps in Google Play einstellen
Pfeil 3.3.3 Alternative Märkte und Ad-hoc-Verteilung
Pfeil 3.4 Zusammenfassung
 
Zum Seitenanfang

3.2    Vom Programm zum Produkt Zur vorigen ÜberschriftZur nächsten Überschrift

Eine Idee in Quelltext umzusetzen, ist für viele Entwickler der interessanteste Teil des Programmierens. Das Erstellen von Tests hingegen, das Suchen und Beheben von Fehlern wird oftmals als eher unangenehme Pflicht angesehen. Wenn Sie Ihre App anderen Personen zugänglich machen möchten, ist eine gewissenhafte Kontrolle aber unerlässlich, sonst droht harsche Kritik. Ein Blick auf die Kommentare in Google Play offenbart, wie viel die Käufer bzw. Nutzer von den Programmierern erwarten.

 
Zum Seitenanfang

3.2.1    Protokollierung Zur vorigen ÜberschriftZur nächsten Überschrift

Allein schon aus Platzgründen kann dieses Buch leider keine Anleitung für das Schreiben von sauberem Code enthalten. Auch wie man Tests entwirft und einsetzt, lesen Sie bei Bedarf in entsprechender Spezialliteratur nach. In Anhang D finden Sie eine Lektüreliste. Aber wie Android Sie beim Aufspüren von Problemen unterstützt und wie Sie Ihre Apps auf echter Hardware und im Emulator testen, zeige ich Ihnen in diesem sowie dem folgenden Abschnitt.

Kotlin-Entwickler verwenden zur schnellen Analyse oder Protokollierung gern die Funktion println(), die natürlich auch unter Android funktioniert. Um das auszuprobieren, legen Sie mit dem Android-Studio-Projektassistenten ein neues Projekt namens DebugDemo an. Verwenden Sie am besten die Ihnen bereits bekannte Vorlage Empty Activity. Nach dem Anlegen des Projekts fügen Sie vor der schließenden Klammer des Methodenrumpfes von onCreate() dieses Quelltextfragment ein:

var fakultaet = 1
println("0! = $fakultaet")
for (i in 1..5) {
fakultaet *= i
println("$i! = $fakultaet")
}

Listing 3.7    Berechnung und Ausgabe der Fakultät

Wenn Sie die App im Emulator oder auf echter Hardware ausführen, sehen Sie die berechneten Fakultäten zunächst nicht. Sie werden aber im Werkzeugfenster Logcat ausgegeben. Es ist in Abbildung 3.3 dargestellt. Falls es nicht geöffnet ist, können Sie es durch Anklicken seines Namens oder über das Pop-up am linken Rand der Statuszeile sichtbar machen.

Das Werkzeugfenster »Logcat«

Abbildung 3.3    Das Werkzeugfenster »Logcat«

Das Fenster besteht aus einer ganzen Reihe von Symbolen am linken Rand (beispielsweise eine Kamera zum Anfertigen eines Screenshots) sowie mehreren Klapplisten am oberen Rand. Im größten Bereich erscheinen Hinweis-, Warn- und Fehlermeldungen. Woher die anzuzeigenden Daten kommen, stellen Sie mit den beiden Klapplisten in der linken oberen Ecke ein. Die erste wählt das Android-Gerät aus, die zweite (rechts neben ihr) den zu beobachtenden Prozess. Die zuletzt gestartete App ist voreingestellt. Logcat sammelt Protokollausgaben des Systems und aller Anwendungen. Es liegt auf der Hand, dass eine solche Darstellung recht schnell unübersichtlich wird. Aus diesem Grund lassen sich Ausgaben beispielsweise nach Prozess-ID, Loglevel oder Paketnamen filtern. Zusätzlich zu den eingebauten Filterkriterien (zum Beispiel Show only selected application) können Sie eigene erstellen. Öffnen Sie hierzu die Aufklappliste in der rechten oberen Ecke des Werkzeugfensters, und wählen Sie Edit Filter Configuration. Sie sehen den in Abbildung 3.4 dargestellten Dialog Create New Logcat Filter.

Dialog zum Anlegen und Bearbeiten von Filtern

Abbildung 3.4    Dialog zum Anlegen und Bearbeiten von Filtern

Um die Ausgabe auf Meldungen zu beschränken, die ein bestimmtes Projekt betreffen, können Sie in Package Name den korrespondierenden Paketnamen eintragen, aber das kann Android Studio auch schon »out of the box«. Spannender sind spezielle Filter, die die Anzeige radikal reduzieren. Wenn Sie in das Feld Log Message beispielsweise den Text »!=« eintragen, so werden nur noch Ausgaben angezeigt, die diese Zeichenkette enthalten. Oder Sie könnten als Log Tag »System.out« eintragen. Das Ergebnis ist in Abbildung 3.5 zu sehen.

Haben Sie in Abbildung 3.3 und Abbildung 3.5 die unscheinbare Klappliste entdeckt, in der Verbose ausgewählt war? Sie enthält die Stufen (Loglevel) verbose, debug, info, warn, error und assert, die in gängigen Frameworks verwendet werden, um die Wichtigkeit bzw. den Schweregrad eines Protokolleintrags zu bestimmen. Die Idee ist, für entsprechende Ausgaben nicht mit println() zu arbeiten, sondern mit speziellen Logging-Methoden.

Logmeldungen der App »DebugDemo«

Abbildung 3.5    Logmeldungen der App »DebugDemo«

Android stellt mit der Klasse android.util.Log eine besonders einfach zu handhabende Variante zur Verfügung. Deren statische Methoden v(), d(), i(), w() und e() repräsentieren die oben genannten Loglevels. Neben dem auszugebenden Text erwarten sie ein sogenanntes Tag. Es kennzeichnet die Quelle des Protokolleintrags, also im Allgemeinen die Klasse oder Activity.

val TAG = MainActivity::class.simpleName

Anstelle von MainActivity verwenden Sie natürlich den Namen Ihrer Klasse. Übernehmen Sie nun die folgenden Anweisungen in Ihre Activity, und starten Sie danach die App. Bitte denken Sie daran, die Liste der Imports um android.util.Log zu erweitern.

Log.v(TAG, "ausführliche Protokollierung, nicht in Produktion verwenden")
Log.d(TAG, "Debug-Ausgaben")
Log.i(TAG, "Informationen")
Log.w(TAG, "Warnungen")
Log.e(TAG, "Fehler")

Listing 3.8    Erzeugen von Protokolleinträgen

Bitte achten Sie auch darauf, dass kein eigener Filter verwendet wird (Show only selected application ist aktiv) und dass als Loglevel Verbose ausgewählt ist. In diesem Fall sind alle fünf Ausgaben im Bereich Logcat zu sehen. Wählen Sie nun ein Element aus der Aufklappliste aus, um Einträge mit niedrigerer Priorität auszublenden. Haben Sie beispielsweise Info aktiviert, dann sind Aufrufe, die durch die Methoden v() (verbose) und d() (debug) erzeugt wurden, nicht zu sehen. Ein Klick auf Verbose zeigt wieder alle Zeilen an. Sie sollten überlegen, welche Meldungen Ihrer App vor allem für die Entwicklung relevant sind. Diese können Sie den Methoden v() und d() übergeben. Für Warnungen und Fehler sind w() und e() gedacht.

Ob ein bestimmter Loglevel in Verbindung mit einem TAG überhaupt protokolliert wird, können Sie mithilfe der Methode isLoggable() abfragen. Der Standardlevel jedes Tags ist INFO. Jeder gleich- oder höherwertige Level wird also geloggt. Wenn Sie das folgende Codefragment Ihrem Projekt hinzufügen, sehen Sie die korrespondierende Ausgabe deshalb zunächst nicht, selbst wenn Sie in der Klappliste Verbose eingestellt haben.

if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "noch eine Debug-Ausgabe")
}

Listing 3.9    Steuerung einer Logausgabe

Sie können dieses Verhalten ändern, indem Sie im Werkzeugfenster Terminal den Befehl adb shell setprop log.tag.<IHR_TAG> <LEVEL> ausführen, zum Beispiel adb shell setprop log.tag.MainActivity VERBOSE. Aufrufe von d() und v() sollten Sie deshalb auf jeden Fall mit isLoggable() klammern.

[+]  Tipp

Manchmal scheinen Logausgaben bei mehrfachen Programmstarts nicht angezeigt zu werden. Der Grund hierfür liegt im Lebenszyklus von Activities. Deren Methode onCreate() wird nicht immer aufgerufen, und zwar ganz bewusst. Wenn Sie also in dieser Methode loggen, kann es durchaus passieren, dass der Code nicht immer durchlaufen wird. Sie können dies ganz leicht erzwingen, indem Sie im Emulator einfach auf den Startbildschirm wechseln. Die Klasse MainActivity meines Beispielprojekts DebugDemo ruft die Methode finish() auf, und dies beendet eine Activity.

Wenn Sie in Ihrem Code eine Exception gefangen haben, müssen Sie übrigens nicht mühselig einen passenden String zusammensetzen, sondern können sie als zusätzlichen Parameter an die Ihnen bereits bekannten fünf Methoden übergeben. Auch hierzu ein Beispiel:

val s: String? = null
try {
Log.d(TAG, "s ist ${s!!.length} Zeichen lang")
} catch (e: NullPointerException) {
Log.e(TAG, "Es ist ein Fehler aufgetreten.", e)
} finally {
Log.d(TAG, "s ist $s")
}

Listing 3.10    Ausgeben eines Stacktrace im Fehlerfall

Da der nullbare String s mit null initialisiert wurde, ist eine NullPointerException unausweichlich. Sie wird aufgrund des catch (e: NullPointerException) gefangen und mittels e() als Fehler protokolliert. Klicken Sie einen Link im Stacktrace an, um zur korrespondierenden Zeile im Quelltext zu navigieren.

 
Zum Seitenanfang

3.2.2    Fehler suchen und finden Zur vorigen ÜberschriftZur nächsten Überschrift

Protokolldateien sind ein wichtiges Hilfsmittel bei der Analyse von Anwendungsproblemen. Allerdings können und sollen sie die klassische Fehlersuche mit dem Debugger nicht ersetzen. Wie Sie Bugs auf Quelltextebene zu Leibe rücken, zeige ich Ihnen nun am Beispiel des Projekts FibonacciDemo. Die Fibonacci-Folge ist eine unendliche Folge von Zahlen, bei der sich die jeweils folgende Zahl durch Addition ihrer beiden Vorgänger ergibt. Für n größer oder gleich 2 gilt demnach: fib(n) = fib(n 1) + fib(n – 2). Für die beiden Spezialfälle 0 und 1 wurde fib(0) = 0 und fib(1) = 1 festgelegt. Der Aufruf fib(5) ergibt also 5. Im Folgenden finden Sie eine Implementierung des Algorithmus. Es handelt sich um eine – Sie ahnen es sicher – fehlerhafte Version.

package com.thomaskuenneth.androidbuch.fibonaccidemo

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

val TAG = FibonacciDemoActivity::class.simpleName
class FibonacciDemoActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.i(TAG, "fib(5) = " + fib(5))
}

private fun fib(n: Int): Int {
Log.i(TAG, "n=$n")
return when (n) {
0 -> 1
1 -> 1
else -> fib(n - 1) + fib(n - 2)
}
}
}

Listing 3.11    Die Klasse »FibonacciDemoActivity«

Starten Sie die App, um zu sehen, zu welchem Ergebnis sie kommt. Denken Sie daran, dass der berechnete Wert nicht direkt im Emulator angezeigt wird, sondern im Werkzeugfenster Logcat. Leider ist dort eine 8 zu lesen. Lassen Sie uns deshalb mithilfe der Einzelschritt-Abarbeitung herausfinden, was passiert. Setzen Sie als Erstes einen Line Breakpoint in der Zeile return when (n) { der Methode fib(), indem Sie im Randbereich des Editorfensters in dieser Zeile mit der linken Maustaste klicken. Wenn der Haltepunkt angelegt wurde, erscheint an der entsprechenden Position ein ausgefüllter roter Kreis. Berühren Sie ihn mit der Maus, um den in Abbildung 3.6 dargestellten Tooltip einzublenden. Die angezeigte Zeilennummer kann bei Ihnen geringfügig abweichen.

Ein Haltepunkt in der Methode »fib()«

Abbildung 3.6    Ein Haltepunkt in der Methode »fib()«

Jetzt können Sie die App debuggen. Klicken Sie hierzu in der Menüleiste auf RunDebug app. Nach kurzer Zeit öffnet Android Studio das Werkzeugfenster Debug und hält die Programmausführung in der Zeile mit dem Haltepunkt an. Die Möglichkeiten, die der Debugger bietet, sind viel zu umfassend, um sie in diesem Buch mehr als nur andeuten zu können. Ein paar wichtige Handgriffe möchte ich Ihnen aber auf jeden Fall nahebringen. Sie können sich zum Beispiel sehr einfach den aktuellen Wert einer Variablen anzeigen lassen, indem Sie die Maus im Editorfenster auf den Variablennamen bewegen. Nach dem ersten Halt ist n gleich 5. Dies ist in Abbildung 3.7 zu sehen.

Android Studio nach dem Start des Debug-Vorgangs

Abbildung 3.7    Android Studio nach dem Start des Debug-Vorgangs

Das Werkzeugfenster Debug enthält die Registerkarten Debugger und Console. Auf der Konsole werden Statusmeldungen der SDK-Tools ausgegeben. Beispielsweise sehen Sie hier, was geschieht, während eine App installiert wird. Auch Log-Ausgaben erscheinen hier, zusätzlich natürlich im Ihnen bereits bekannten Werkzeugfenster Logcat. Die Steuerung des Debuggers erfolgt mithilfe von Symbolen am linken (Programmablauf) und oberen (Einzelschrittverarbeitung) Rand des Werkzeugfensters. Die wichtigsten Symbole sind in Tabelle 3.1 zu sehen.

Symbol

Funktion

Resume Program

Pause Program

Stop

Step Over

Step Into

Tabelle 3.1    Wichtige Symbole des Debuggers

Klicken Sie auf Step Over oder drücken Sie (F8), um die nächste Anweisung auszuführen. Dies ist else -> fib(n - 1) + fib(n - 2). Mit Resume Program ((F9)) lassen Sie das Programm bis zum Erreichen des nächsten Haltepunktes ohne Unterbrechung weiterlaufen. Wiederholen Sie die Schritte mit Step Over und Resume so lange, bis n den Wert 1 hat. Nun führt Sie ein Step Over in die Zeile 1 -> 1. Dies ist erwartetes Verhalten, deshalb können Sie die App mit Resume fortsetzen. Da 0 die letzte zu verarbeitende Zahl ist, müsste der Fehler jetzt auftreten. Nachdem das Programm durch den Debugger angehalten wurde, führt ein Step Over zur Zeile 0 -> 1. Es wird also 1 zurückgegeben. Das ist aber natürlich falsch, denn fib(0) muss 0 ergeben. Beenden Sie den Debug-Vorgang, indem Sie das Symbol Stop anklicken. Korrigieren Sie die fehlerhafte Zeile, und starten Sie die App erneut. In Logcat wird nun der richtige Wert 5 angezeigt.

Wenn Sie die Situation, in der ein Fehler auftritt, eingrenzen können, reduzieren bedingte Haltepunkte den Aufwand beim Debuggen erheblich. Nehmen wir an, Sie wussten, dass Sie das Problem am besten untersuchen können, wenn n den Wert 0 hat. Dann ist es unnötig, bis zum Eintreten dieser Konstellation dem Programmablauf schrittweise zu folgen. Bewegen Sie den Mauszeiger im Kotlin-Editor über das Breakpoint-Symbol, und drücken Sie die rechte Maustaste. Geben Sie im daraufhin erscheinenden Pop-up bei Condition den Ausdruck n == 0 ein, schließen Sie es mit Done, und starten Sie den Debug-Vorgang nun erneut. Die Programmausführung wird erst angehalten, wenn die formulierte Bedingung erfüllt ist.

 
Zum Seitenanfang

3.2.3    Debuggen auf echter Hardware Zur vorigen ÜberschriftZur nächsten Überschrift

Wenn Sie ein Android-Smartphone oder -Tablet besitzen, können Sie die eben vorgestellte App direkt auf diesem Gerät debuggen. Gerade Programme, die Sie an andere weitergeben möchten, sollten Sie solchen Tests unterziehen.

Unter Windows müssen Sie vor der erstmaligen Nutzung des Geräts am USB-Port Ihres Rechners möglicherweise einen aktualisierten Treiber installieren. Welcher dies ist, können Sie hoffentlich der Dokumentation zu Ihrem Smartphone oder Tablet entnehmen.

Nun müssen Sie auf dem Gerät das USB-Debugging aktivieren. Öffnen Sie hierzu die Einstellungen, wählen Sie zuerst System und danach Entwickleroptionen. Sollten diese nicht angezeigt werden, müssen Sie sie erst freischalten. Dies gilt übrigens auch für den Emulator. Auf der Seite System finden Sie Über das Telefon. Wechseln Sie bitte dorthin, und tippen Sie dann Build-Nummer siebenmal an. Aktivieren Sie, wie in Abbildung 3.8 dargestellt, USB-Debugging.

Wenn Sie möchten, können Sie mit Aktiv lassen konfigurieren, dass die Anzeige des Geräts nicht in den Ruhezustand versetzt wird. Kehren Sie danach zum Startbildschirm zurück. Bitte beachten Sie, dass die Texte je nach Modell leicht abweichen können.

Die Seite »Entwickleroptionen« der Android-Einstellungen

Abbildung 3.8    Die Seite »Entwickleroptionen« der Android-Einstellungen

Wählen Sie nun, wie in Abbildung 3.9 dargestellt, Ihr Gerät aus, und starten Sie danach den Debug-Vorgang mit RunDebug App.

Wählen Sie hier das Gerät aus, das Sie verwenden wollen.

Abbildung 3.9    Wählen Sie hier das Gerät aus, das Sie verwenden wollen.

Zum Schluss noch ein Tipp: Die Höhe des Werkzeugfensters Debug hat Einfluss auf die Anzahl der Symbole, die am linken Rand angezeigt werden. Falls nicht alle sichtbar sind, erscheinen zwei nach rechts weisende spitze Pfeile (inline image). Bewegen Sie den Mauszeiger auf dieses Symbol, öffnet sich ein Pop-up mit den verdeckten Funktionen. Wie dies aussehen kann, ist in Abbildung 3.10 dargestellt.

Pop-up mit verdeckten Symbolen

Abbildung 3.10    Pop-up mit verdeckten Symbolen

Damit verlassen wir den Bereich der Fehlersuche. Im folgenden Abschnitt zeige ich Ihnen, wie Sie Ihre fertige App verteilen und in Google Play einem riesigen Publikum vorstellen.

 


Ihre Meinung?

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de

<< zurück
Zur Rheinwerk-Konferenz für Kotlin
 Buchempfehlungen
Zum Rheinwerk-Shop: Kotlin

Kotlin


Zum Rheinwerk-Shop: Praxisbuch Usability und UX

Praxisbuch Usability und UX


Zum Rheinwerk-Shop: Flutter und Dart

Flutter und Dart


Zum Rheinwerk-Shop: App-Design

App-Design


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und in die Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2023
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern