Skip to content

Commit

Permalink
add concept subsection about viewmodels and their usage
Browse files Browse the repository at this point in the history
  • Loading branch information
felix-kaestner committed Mar 4, 2021
1 parent 35ad217 commit 1739d8c
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 4 deletions.
Binary file added images/fragment_viewmodels.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/viewmodel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 30 additions & 2 deletions sections/04_concept.tex
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ \section{Umsetzung der Ansichten}

Mit der vorliegenden Konzeption zur Unterteilung der Komponenten und den etablierten Richtlinien begann die Umsetzung der Ansichten. Die Implementation der Ansichten fand dabei zunächst unabhängig vom Datenbank-Backend statt. Stattdessen wurden Beispieldaten verwendet, um die Views zu generieren. Gleichzeitig wurde allerdings bereits großer Wert auf die Strukturierung der ViewModels gelegt, um im späteren Verlauf die Beispieldaten auf einfache Weise durch das Datenbank-Backend ergänzen zu können. Dadurch ergaben sich die Vorteile im Entwicklungsprozess, da die Ansichten in einem schnelleren Entwicklungszyklus erstellt werden konnten und die notwendige Separation leichter umsetzbar war. Im Folgenden konnte bereits nach wenigen Wochen die Benutzeroberfläche zwischen der iOS und Android App abgeglichen werden.

\subsection{Erstellung von Fragments}
\subsection{Erstellung von Fragments}\label{sub:fragments}

Um die in \Cref{subsec:viewbinding} und \Cref{subsec:databinding} vorgestellten Konzepte von Viewbinding und Databinding zu Nutzen, empfiehlt die offizielle Dokumentation\footnote{Viewbinding in Fragments. \url{https://developer.android.com/topic/libraries/view-binding\#fragments}} die Nutzung von \texttt{Backing-Properties}\footnote{Backing-Properties. \url{https://kotlinlang.org/docs/reference/properties.html\#backing-properties}} in Kotlin.Dabei entsteht inhärent eine gewisse Verbosität. Damit diese Umstände vermieden werden konnte, wurde eine entsprechende Lösung anhand der Klasse \texttt{AutoClearedValue} eingeführt. Diese Klasse beobachtet einfach den Lebenszyklus des Fragments und invalidiert Zugriffe, sobald sich das Fragment im \texttt{onDestroy}-Status befindet. Mittels einer \texttt{Extension}\footnote{Extension. \url{https://kotlinlang.org/docs/extensions.html}} konnte die Verwendung der Klasse über \texttt{Delegated Properties}\footnote{Delegated Properties. \url{https://kotlinlang.org/docs/reference/delegated-properties.html}} bereitgestellt werden. Anhand des in \Cref{subsec:delegation} beschrieben Pattern von Delegation kann die entsprechende Variable in die Nutzung innerhalb der Fragment-Klasse eingebunden werden. Da es sich im Allgemeinen empfiehlt während der \texttt{onCreateView} eines Fragments nur äußerst sparsame Operationen vorzunehmen und stattdessen komplexe Anwendungslogik in die \texttt{onViewCreated} auszulagern, ergibt sich folgender Aufbau der Ansichten:

Expand All @@ -63,9 +63,37 @@ \subsection{Erstellung von Fragments}

In \Cref{fig:fragment} zu sehen ist ein Ausschnitt des Quellcodes der Home-Ansicht. Dabei zu sehen ist die Nutzung des in \Cref{subsec:delegation} vorgestellten Prinzips von Delegation zur Bereitstellung der Klassen-Member. Neben der Verwendung der Methode \texttt{autoCleared()} zur Erstellung einer Instanz der Klasse \texttt{AutoClearedValue} wie oben beschrieben, ist auch die Delegation zur Erstellung von ViewModel-Instanzen zu sehen. Dies geschieht mittels der Methoden \texttt{viewModels()} und \texttt{activityViewModels()} die als Teil von Android KTX\footnote{Android KTX \url{https://developer.android.com/kotlin/ktx}} bereitstehen.

\subsection{Verwendung von Viewmodels}
\subsection{Verwendung von Viewmodels}\label{sub:viewmodel_usage}

Für die Bereitstellung von Daten mittels des entwickelten Datenbank-Frameworks wurde Kotlin \texttt{Coroutines}\footnote{Coroutines. \url{https://kotlinlang.org/docs/coroutines-overview.html}} zurückgegriffen. Couchbase bietet die Möglichkeit zur Erstellung von sogenannten \texttt{Live Query}\footnote{Live Query. \newline \url{https://docs.couchbase.com/couchbase-lite/current/android/learn/java-android-query-live.html}} Objekten. Dabei wird ein \texttt{Listener} auf einer beliebigen Datenbankabfrage abgewendet. Sobald sich im Folgenden das Resultat der Datenbankabfrage ändert, wird ein entsprechender \texttt{Callback} ausgeführt. Diese Funktionalität wurde seitens des Datenbank-Frameworks gekapselt und im Allgemeinen unter den \texttt{addOnChangeListener}-Funktionen der Repository-Klasse zur Verfügung gestellt. Des Weiteren lässt sich diese Callback-basierte Asynchronität in einen asynchronen Datenfluss umwandeln. Kotlin führt dazu im Rahmen von \texttt{Coroutines} eine Datenstruktur für die Verwendung von asynchronen Datenfüssen namens \texttt{Flow}\footnote{Asynchronous Flow. \url{https://kotlinlang.org/docs/flow.html}} ein. Das Prinzip eines solchen Datenflusses ist äquivalent zu bekannten Lösungen wie \texttt{RxJava}\footnote{RxJava \url{https://github.com/ReactiveX/RxJava}}. Damit bietet \texttt{Flow} die Grundlage für asynchrone und Event-basierte Programmierung in Kotlin. Ein großer Vorteil von \texttt{Flow} ist das die Verarbeitung von Elementen ausgesetzt werden kann und in diesem Zustand den Main-Thread der Applikation, welcher für die UI zuständig ist, nicht blockiert. Ein weiterer Vorteil von \texttt{Flow}s ist diese sogenannte \enquote{cold streams} repräsentieren. Dabei werden Elemente erst transferiert, sobald ein entsprechender Empfänger vorhanden ist und diese verarbeitet. Im Falle der Android-App bedeutet dieser Sachverhalt, das Objekte erste bei entsprechender Ansicht in App von der Datenbank geladen werden. Die Verarbeitung der Elemente eines \texttt{Flow} geschieht wie auch die Ausführung einer \texttt{Coroutine} in einem entsprechenden Kontext. Dieser Kontext ist verantwortlich für die Koordination der Ausführung. Für den \texttt{CoroutineContext} stehen in der Android-Platform potenziell mehrere Optionen zur Verfügung, die für unterschiedliche Anwendungsszenarien geeignet sind.

\begin{itemize}
\item \textbf{Dispatchers.Default} bildet den Standardwert, welcher automatisch genutzt wird, sollte kein anderer \texttt{CoroutineContext} explizit angegeben werden. Dieser Kontext sollte nur zu Testzwecken genutzt werden und die explizite Zuweisung eines Kontext bevorzugt werden.
\item \textbf{Dispatchers.Main} führt \texttt{Coroutines} auf dem Main-Thread der Applikation aus, der für die UI zuständig ist. Normalerweise handelt es sich hierbei um einen einzelnen Thread, der die Aufgaben sequentiell bearbeitet. Im Falle von Android sollte stattdessen die Benutzung von \texttt{Dispatchers.Main.immediate} bevorzugt werden.
\item \textbf{Dispatchers.Main.immediate} ist eine Erweiterung des \texttt{Dispatchers.Main} der lediglich auf der JVM und Android nutzbar ist. Dabei werden Aufgaben unverzüglich ausgeführt. Dieser Kontext sollte daher für Operationen genutzt werden, die im direkten Zusammenhang mit der UI stehen, wie beispielsweise die Durchführung eines HTTP-Request zur Registrierung des Spielers. \newpage
\item \textbf{Dispatchers.Unconfined} gibt keine Aussage über die Ausführung. Stattdessen wird der aktuelle Thread für die Ausführung genutzt ohne jegliche Richtlinien zu setzen. Dieser unspezifische Kontext sollte ebenso vermieden werden.
\item \textbf{Dispatchers.IO} führt Aufgaben auf einem Hintergrund-Prozess aus. Das kann Vorteilhaft sein um blockierende Aufrufe wie das Lesen von Dateien oder den Zugriff auf die Datenbank durchzuführen. Der Kontext verwendet dazu einen geteilten \enquote{Pool} von Threads die für die Ausführung herangezogen werden. Weitere Threads können bei Bedarf erstellt und nach Verwendung zerstört werden.
\end{itemize}

Entsprechend ergibt sich für die Verwendung von \texttt{Coroutines} in ViewModels die Nutzung von \textbf{Dispatchers.Main.immediate} für die Deklaration von Methoden, welche direkt von der View aufgerufen werden sollen sowie \textbf{Dispatchers.IO} für Generierung eines \texttt{Flow}, welcher eine konstante Aktualisierung von Elemente (wie den Events der Programm-Ansicht) im Hintergrund ausführen soll. \newline Um die Elemente eines solchen Datenstroms anschließend nutzen zu können, werden diese in ein \texttt{LiveData}\footnote{LiveData. \url{https://developer.android.com/topic/libraries/architecture/livedata}}-Objekt konvertiert. \Cref{fig:viewmodel} zeigt die daraus resultierende Definition eines ViewModels in der App.

\begin{figure}[H]
\includegraphics[width=1\linewidth]{viewmodel.png}
\caption{Erstellung von ViewModels für die OUTPUT-App.}\label{fig:viewmodel}
\end{figure}

Die \texttt{LiveData}-Objekte können im folgenden genutzt werden, um die Ansichten zu erstellen. Dabei werden die Objekte nach dem in \Cref{sub:observer} beschriebenen Observer-Entwurfsmuster überwacht. Sobald sich im Folgenden die Daten dieser Objekte ändert, wird eine Aktualisierung der Ansicht durchgeführt. Dies geschieht im Falle der Verwendung von \hyperref[subsec:databinding]{Databinding} automatisch wie in \Cref{fig:fragment_viewmodels} anhand des \texttt{PlayerViewModel} zu sehen, welches automatisch die Spielansicht aktualisiert oder im Falle einer Listenansicht durch die Weitergabe der Objekte durch das Fragment, wie in \Cref{fig:fragment_viewmodels} anhand des \texttt{GameRewardViewModel} zu sehen. Bei letzterem geschieht die Generierung der Darstellung einzelner Elemente wie in \Cref{fig:databinding} zu sehen.

\begin{figure}[H]
\includegraphics[width=1\linewidth]{fragment_viewmodels.png}
\caption{Nutzung von ViewModels für die OUTPUT-App.}\label{fig:fragment_viewmodels}
\end{figure}

\subsection{Definition der Ansichten}

Mittels der in \Cref{sub:fragments} und \Cref{sub:viewmodel_usage} vorgestellten Konzepte und Implementierungen konnten die Ansichten der App definiert werden. \Cref{fig:fragment_viewmodels} zeigt die 5 Hauptansichten der App. Weitere Ansichten wurden entsprechend der Dialoglandkarte aus \Cref{se:map} umgesetzt. Der Aufbau der Ansicht orientiert sich an der Implementation der vorangegangenen Jahre. Allerdings wurde im Rahmen der Neuimplementation auch eine Modernisierung der Benutzeroberfläche durchgeführt. Darunter ergeben sich auch neue Funktionen wie ein dunkles Design, welches automatisch durch die Systemeinstellung des Nutzers aktiviert wird und bei Dunkelheit die Augen vor zu viel Helligkeit schützt. Außerdem wurde eine Reihe von Animationen eingeführt, welche die Nutzererfahrung steigern und die Nutzerinteraktion unterstützen. Im Sinne der Grundprinzipien des Usability Engineerings wurde ebenso auf die Platzierung von Interaktionselementen in der unteren Hälfte des Bildschirms geachtet, um für den Nutzer leichter erreichbar zu sein. Für eine konsistente Nutzererfahrung sorgt auch die Modularisierung von UI-Komponenten sowie die Erstellung von generischen Klassen, welche für mehrere Ansichten in der App wiederverwendet wurde. Zur Bereitstellung eines Themes wurde auf ein Theme der \texttt{Material Design}\footnote{Material Design. \url{https://material.io/resources/build-a-material-theme}} Bibliothek als Grundlage zurückgegriffen, um dem Nutzer eine plattformspezifische Erfahrung zu bieten. Gleichzeitig wurde bei der Auswahl der Formen, Farben und Fonts auf die Vorgaben aus der OUTPUD.DD Corporate Identity geachtet. Neben der Neuimplementation des gesamten UI, inklusive komplexerer Ansichten wie die \enquote{Reward-Ansicht} mit einer Konfetti-Animation, wurde in der Kartenansicht \texttt{Google Maps} durch \texttt{Mapbox}\footnote{Mapbox \url{https://www.mapbox.com/}} ersetzt, da das Mapbox-Framework durch seine Nutzerfreundlichkeit und einfachen Handhabung im Projektteam befürwortet wurde. Auch die Twitter-Ansicht wurde erneuert. Statt der Verwendung des mittlerweile eingestellten Twitter-Frameworks wurde eine rein auf HTML basierende Lösung entwickelt. Dabei wird ein HTML-Template in einer \texttt{Webview}\footnote{Webview. \url{https://developer.android.com/reference/android/webkit/WebView}} dargestellt. Durch diese Implementierung wird kein API-Schlüssel benötigt und konnte zugleich eine zukunftssichere Lösung geschaffen werden.

\newpage

\section{Anbindung der Gamification}

Expand Down
4 changes: 2 additions & 2 deletions thesis.tex
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@
\listoffigures
\addcontentsline{toc}{chapter}{\listfigurename}

\listoftables
\addcontentsline{toc}{chapter}{\listtablename}
% \listoftables
% \addcontentsline{toc}{chapter}{\listtablename}

% this is where your thesis lives

Expand Down

0 comments on commit 1739d8c

Please sign in to comment.