Auch wenn Ihre Anwendung schnell und responsiv ist, können bestimmte Designentscheidungen den Nutzern dennoch Probleme bereiten – durch ungeplante Interaktionen mit anderen Anwendungen oder Dialogfeldern, versehentlichen Datenverlust, unbeabsichtigte Blockierungen usw. Um diese Probleme zu vermeiden, ist es hilfreich, den Kontext zu verstehen, in dem Ihre Anwendungen ausgeführt werden, und die Systeminteraktionen, die sich auf Ihre Anwendung auswirken können. Kurz gesagt sollten Sie versuchen, eine Anwendung zu entwickeln, die nahtlos mit dem System und anderen Anwendungen interagiert.
Ein häufig auftretendes nahtloses Problem tritt auf, wenn der Hintergrundprozess einer Anwendung, z. B. ein Dienst oder Sendeempfänger, ein Dialogfeld als Reaktion auf ein Ereignis öffnet. Dies kann harmlos wirken, insbesondere wenn Sie Ihre Anwendung isoliert auf dem Emulator erstellen und testen. Wenn Ihre Anwendung jedoch auf einem Gerät ausgeführt wird, ist der Nutzer möglicherweise nicht im Fokus, wenn das Dialogfeld im Hintergrundprozess angezeigt wird. Es könnte also sein, dass Ihre Anwendung das Dialogfeld hinter der aktiven Anwendung anzeigt oder den Fokus von der aktuellen Anwendung auf dieses Dialogfeld vor dem zeigt, was der Nutzer gerade getan hat (z. B. einen Anruf). Dieses Verhalten würde für Ihre Anwendung oder den Nutzer nicht funktionieren.
Um diese Probleme zu vermeiden, sollte Ihre Anwendung die richtige Systemfunktion für die Benachrichtigung des Nutzers verwenden – die Notification
-Klassen. Mithilfe von Benachrichtigungen kann Ihre Anwendung dem Nutzer signalisieren, dass ein Ereignis stattgefunden hat, indem ein Symbol in der Statusleiste angezeigt wird, anstatt den Fokus zu legen und den Nutzer zu unterbrechen.
Ein weiteres Beispiel für ein nahtloses Problem ist, wenn eine Aktivität versehentlich Status- oder Nutzerdaten verliert, da onPause() und andere Lebenszyklusmethoden nicht korrekt implementiert werden. Wenn Ihre Anwendung Daten offenlegt, die für die Verwendung durch andere Anwendungen bestimmt sind, sollten Sie diese über einen ContentProvider zur Verfügung stellen, anstatt dies (z. B.) über eine weltlesbare Rohdatei oder -datenbank zu tun.
Diese Beispiele haben gemeinsam, dass sie gut mit dem System und anderen Anwendungen zusammenarbeiten. Das Android-System behandelt Anwendungen als eine Art Verbund aus lose gekoppelten Komponenten und nicht als Blöcke von Blackbox-Code. Auf diese Weise können Sie als Entwickler das gesamte System als eine noch größere Föderation dieser Komponenten betrachten. Sie profitieren dadurch von einer sauberen und nahtlosen Integration in andere Anwendungen. Sie sollten daher Ihren eigenen Code entwerfen, um im Gegenzug Ihren eigenen Code zu erstellen.
In diesem Dokument werden häufige Probleme bei nahtlosem Ablauf und wie sie vermieden werden können.
Keine Daten verwerfen
Denken Sie immer daran, dass Android eine mobile Plattform ist. Es mag offensichtlich erscheinen, aber du solltest bedenken, dass jederzeit eine andere Aktivität (z. B. die App für eingehende Anrufe) in deiner eigenen Aktivität angezeigt werden kann. Dadurch werden die Methoden onSaveInstanceState() und onPause() ausgelöst, was wahrscheinlich dazu führt, dass Ihre App beendet wird.
Wenn der Nutzer Daten in Ihrer App bearbeitet hat, als die andere Activity angezeigt wurde, gehen diese Daten wahrscheinlich verloren, wenn die App beendet wird. Es sei denn, Sie speichern zuerst die laufende Arbeit. Mit Android ist genau das möglich: Android-Apps, die Eingaben annehmen oder bearbeiten, sollten die Methode "onSaveInstanceState()" überschreiben und ihren Status entsprechend speichern. Wenn der Nutzer die Anwendung noch einmal aufruft, sollte er seine Daten abrufen können.
Ein klassisches Beispiel für eine gute Verwendung dieses Verhaltens ist eine E-Mail-Anwendung. Wenn der Nutzer beim Start einer anderen Aktivität eine E-Mail verfasst hat, sollte die Anwendung die laufende E-Mail als Entwurf speichern.
Rohdaten nicht offenlegen
Wenn Sie nicht in Unterwäsche die Straße entlanggehen würden, sollten Ihre Daten auch nicht. Es ist zwar möglich, bestimmte Arten von Anwendungen der Welt zum Lesen zugänglich zu machen, dies ist jedoch in der Regel nicht die beste Idee. Damit Rohdaten verfügbar gemacht werden können, müssen andere Anwendungen das Datenformat verstehen. Wenn Sie dieses Format ändern, funktionieren andere Anwendungen nicht mehr, die nicht in ähnlicher Weise aktualisiert werden.
Die "Android-Möglichkeit" besteht darin, einen ContentProvider zu erstellen, um Ihre Daten über eine saubere, gut durchdachte und zu wartende API für andere Anwendungen freizugeben. Die Verwendung eines ContentProviders ähnelt dem Einfügen einer Java-Schnittstelle, um zwei eng gekoppelte Codeabschnitte aufzuteilen und in Komponenten zu komponentenisieren. Das bedeutet, dass Sie das interne Format Ihrer Daten ändern können, ohne die vom ContentProvider bereitgestellte Schnittstelle zu ändern, und dies ohne Auswirkungen auf andere Anwendungen.
Nutzer nicht unterbrechen
Wenn der Nutzer eine Anwendung ausführt (z. B. die Telefonanwendung während eines Anrufs), ist es ziemlich sicher, dass er dies absichtlich getan hat. Aus diesem Grund sollten Sie das Auslösen von Aktivitäten nur als direkte Reaktion auf Nutzereingaben aus der aktuellen Aktivität vermeiden.
Rufe also nicht startActivity() von BroadcastReceivern oder Diensten auf, die im Hintergrund ausgeführt werden. Dadurch wird die derzeit ausgeführte Anwendung unterbrochen und der Nutzer verärgert. Noch schlimmer ist möglicherweise, dass Ihre Activity-Klasse zu einem Tastaturanschlag-Bandit wird und einen Teil der Eingabe empfängt, die der Nutzer gerade für die vorherige Aktivität bereitgestellt hat. Je nachdem, was Ihre Anwendung tut, kann das schlechte Nachrichten sein.
Anstatt Aktivitäts-UIs direkt aus dem Hintergrund zu erzeugen, solltest du zum Einrichten von Benachrichtigungen den NotificationManager verwenden. Diese werden in der Statusleiste angezeigt und der Nutzer kann sie anklicken, um zu sehen, was ihm in Ihrer App angezeigt wird.
Dies gilt nicht für Fälle, in denen Ihre eigene Activity bereits im Vordergrund steht: In diesem Fall erwartet der Nutzer, dass er als Antwort auf die Eingabe Ihre nächste Activity angezeigt wird.
Sie haben viel zu tun? In einem Thread ausführen
Wenn Ihre Anwendung teure Berechnungen oder Berechnungen mit langer Ausführungszeit durchführen muss, sollten Sie sie wahrscheinlich in einen Thread verschieben. Dadurch wird verhindert, dass dem Nutzer das gefürchtete Dialogfeld „App antwortet nicht“ angezeigt wird, was letztendlich zum blutigen Ableben Ihrer App führt.
Standardmäßig werden der gesamte Code in einer Aktivität sowie alle zugehörigen Ansichten im selben Thread ausgeführt. Dies ist derselbe Thread, der auch UI-Ereignisse verarbeitet. Wenn der Nutzer beispielsweise eine Taste drückt, wird ein Key-Down-Ereignis zur Warteschlange des Hauptthreads der Aktivität hinzugefügt. Das Event-Handler-System muss das Ereignis schnell aus der Warteschlange entfernen und verarbeiten. Andernfalls schließt das System nach einigen Sekunden die Verbindung der Anwendung ab und bietet dem Nutzer an, sie zu beenden.
Wenn Sie lang andauernden Code haben und ihn inline in Ihrer Aktivität ausführen, wird er im Event-Handler-Thread ausgeführt und blockiert den Event-Handler. Dies verzögert die Eingabeverarbeitung und führt zu ANR-Dialogfeldern. Um das zu vermeiden, verschieben Sie Ihre Berechnungen in einen Thread. In diesem Dokument zum Thema Responsivitäts-Design wird beschrieben, wie Sie dies tun können.
Überladen Sie einen Bildschirm mit nur einer Aktivität nicht
Jede Anwendung, die sich lohnt, hat wahrscheinlich mehrere verschiedene Bildschirme. Achten Sie beim Entwerfen der Bildschirme Ihrer UI darauf, mehrere Activity-Objektinstanzen zu verwenden.
Abhängig von Ihrem Entwicklungshintergrund können Sie eine Activity ähnlich wie ein Java-Applet insofern interpretieren, als dass sie der Einstiegspunkt für Ihre Anwendung ist. Dies ist jedoch nicht ganz genau: Wenn eine Applet-Unterklasse der einzige Einstiegspunkt für ein Java-Applet ist, sollte eine Activity als einer von möglicherweise mehreren Einstiegspunkten für Ihre Anwendung betrachtet werden. Der einzige Unterschied zwischen Ihrer „main“-Aktivität und anderen, die Sie haben könnten, besteht darin, dass die „main“-Aktivität die einzige ist, die ein Interesse an der Aktion „android.intent.action.MAIN“ in Ihrer AndroidManifest.xml-Datei zum Ausdruck gebracht hat.
Stellen Sie sich Ihre Anwendung daher beim Entwerfen als Föderation von Activity-Objekten vor. Auf diese Weise ist Ihr Code auf lange Sicht viel leichter zu verwalten. Als positiver Nebeneffekt funktioniert das auch mit dem App-Verlauf und dem Backstack-Modell von Android gut.
Systemdesigns erweitern
Es ist wichtig, dass sich die Benutzeroberfläche gut in das Erscheinungsbild der Benutzeroberfläche einfügt. Nutzer werden durch Anwendungen abgelenkt, die im Gegensatz zu der gewohnten Benutzeroberfläche stehen. Beim Entwerfen von UIs sollten Sie nach Möglichkeit keine eigenen UI-Elemente erstellen. Verwenden Sie stattdessen ein Design. Sie können die gewünschten Teile des Designs zwar überschreiben oder erweitern, aber zumindest fangen Sie mit derselben UI-Basis wie bei allen anderen Anwendungen an. Alle Einzelheiten finden Sie unter Stile und Designs.
Benutzeroberfläche für unterschiedliche Bildschirmauflösungen entwerfen
Verschiedene Android-Geräte unterstützen unterschiedliche Bildschirmauflösungen. Einige können die Auflösungen sogar spontan ändern, z. B. durch Wechseln in das Querformat. Layouts und Drawables müssen flexibel genug sein, damit sie auf einer Vielzahl von Gerätebildschirmen richtig angezeigt werden können.
Glücklicherweise ist das ganz einfach. Kurz gesagt: Du musst gegebenenfalls verschiedene Versionen deiner Grafik für die wichtigsten Auflösungen bereitstellen und dann dein Layout so gestalten, dass verschiedene Abmessungen berücksichtigt werden. Vermeiden Sie beispielsweise hartcodierte Positionen. Verwenden Sie stattdessen relative Layouts. In diesem Fall übernimmt das System den Rest und Ihre Anwendung sieht auf jedem Gerät gut aus.
Angenommen, das Netzwerk ist langsam
Android-Geräte sind mit einer Vielzahl von Optionen für die Netzwerkverbindung ausgestattet. Alle haben einen gewissen Datenzugriff, aber einige sind schneller als andere. Der kleinste gemeinsame Nenner ist jedoch GPRS, der Nicht-3G-Datendienst für GSM-Netzwerke. Selbst 3G-fähige Geräte verbringen viel Zeit in Nicht-3G-Netzwerken, sodass langsame Netzwerke noch lange Realität werden werden.
Daher sollten Sie Ihre Anwendungen immer codieren, um Netzwerkzugriffe und Bandbreite zu minimieren. Sie können nicht davon ausgehen, dass das Netzwerk schnell ist, daher sollten Sie immer ein langsames Netzwerk einplanen. Wenn Ihre Nutzer schnellere Netzwerke nutzen, ist das toll – die Nutzererfahrung wird sich weiter verbessern. Umgekehrt sollten Sie jedoch das Umkehren vermeiden: Anwendungen, die zwar manchmal nutzbar sind, den Rest aber verlangsamt – je nachdem, wo sich der Nutzer zu einem bestimmten Zeitpunkt befindet, werden wahrscheinlich unbeliebt sein.
Ein mögliches Problem ist, dass es sehr leicht ist, in diesen Fallstrick zu geraten, wenn Sie den Emulator verwenden, da er die Netzwerkverbindung Ihres Desktop-Computers verwendet. Das ist mit ziemlicher Sicherheit viel schneller als ein Mobilfunknetz, sodass Sie die Einstellungen im Emulator ändern sollten, die niedrigere Netzwerkgeschwindigkeiten simulieren. Dazu können Sie in Android Studio den AVD-Manager oder eine Befehlszeilenoption verwenden, wenn Sie den Emulator starten.
Nicht davon ausgehen, Touchscreen oder Tastatur zu verwenden
Android unterstützt eine Vielzahl von Formfaktoren auf Mobilgeräten. So könnte man sagen, dass einige Android-Geräte über vollständige QWERTY-Tastaturen verfügen, während andere über 40-, 12- oder sogar andere Tastenkonfigurationen verfügen. Genauso haben einige Geräte einen Touchscreen, viele aber nicht.
Berücksichtigen Sie dies beim Erstellen von Anwendungen. Machen Sie keine Annahmen über bestimmte Tastaturlayouts – es sei denn, Sie sind wirklich daran interessiert, Ihre App so einzuschränken, dass sie nur auf diesen Geräten verwendet werden kann.
Geräteakku schonen
Ein Mobilgerät ist nicht sehr mobil, wenn es ständig an die Wand angeschlossen ist. Mobilgeräte sind akkubetrieben. Je länger der Akku geladen werden muss, desto glücklicher sind alle – vor allem die Nutzer. Zwei der größten Batterieverbraucher sind der Prozessor und das Funkgerät. Deshalb ist es wichtig, Ihre Anwendungen so zu entwickeln, dass sie so wenig Arbeit wie möglich ausführen und das Netzwerk so selten wie möglich nutzen.
Wenn Sie die Prozessorzeit Ihrer Anwendung minimieren möchten, kommt es darauf an, effizienten Code zu schreiben. Gehen Sie mit Fehlerbedingungen ordnungsgemäß um und rufen Sie nur die Daten ab, die Sie benötigen, um den Stromverbrauch auf ein Minimum zu reduzieren. Wiederholen Sie beispielsweise nicht ständig einen Netzwerkvorgang, wenn dieser fehlgeschlagen ist. Wenn ein Fehler einmal auftritt, liegt das wahrscheinlich daran, dass der Nutzer keinen Empfang hat. In diesem Fall wird es wahrscheinlich noch einmal fehlschlagen, wenn Sie es sofort versuchen. Sie müssen lediglich Akkuleistung verschwenden.
Nutzer sind ziemlich schlau: Wenn Ihr Programm viel Energie benötigt, können Sie sich darauf verlassen, dass sie es bemerken. Sie können an diesem Punkt nur sicher sein, dass Ihr Programm nicht sehr lange installiert bleibt.