diff --git a/images/generic.pdf b/images/generic.pdf new file mode 100644 index 0000000..7a462c9 Binary files /dev/null and b/images/generic.pdf differ diff --git a/images/metaframework.pdf b/images/metaframework.pdf new file mode 100644 index 0000000..f6624c2 Binary files /dev/null and b/images/metaframework.pdf differ diff --git a/images/metastruktur.pdf b/images/metastruktur.pdf new file mode 100644 index 0000000..75269cc Binary files /dev/null and b/images/metastruktur.pdf differ diff --git a/images/mindmap.pdf b/images/mindmap.pdf new file mode 100644 index 0000000..22737e2 Binary files /dev/null and b/images/mindmap.pdf differ diff --git a/images/mvvm.png b/images/mvvm.png new file mode 100644 index 0000000..41d5fe1 Binary files /dev/null and b/images/mvvm.png differ diff --git a/images/navigation.png b/images/navigation.png index 1608013..ed7cf67 100644 Binary files a/images/navigation.png and b/images/navigation.png differ diff --git a/images/observer.png b/images/observer.png new file mode 100644 index 0000000..a6b31ec Binary files /dev/null and b/images/observer.png differ diff --git a/sections/02_basics.tex b/sections/02_basics.tex index 5d01611..db2f99c 100644 --- a/sections/02_basics.tex +++ b/sections/02_basics.tex @@ -15,7 +15,7 @@ \section{Kotlin} \section{Grundlagen der Android-Entwicklung} -Im Folgenden sollen zunächst die wesentlichsten Grundlagen der Android-Entwicklung und der Aufbau einer Android-App erläutert werden. Anschließend werden verschiedene Patterns vorgestellt, die sich im Implementationskonzept wiederfinden und auch Bestandteil der zukünftigen Entwicklung sein sollen. +Im Folgenden sollen zunächst die wesentlichsten Grundlagen der Android-Entwicklung und der Aufbau der Android-App erläutert werden. Anschließend werden verschiedene Bibliotheken vorgestellt, welche die Grundlage der Implementation bilden. \subsection{Erstellung von Views} @@ -78,21 +78,21 @@ \subsection{Navigation} \item \textbf{NavController:} Ein Objekt, das die App-Navigation innerhalb eines NavHosts verwaltet. Der NavController orchestriert das Austauschen von Zielinhalten im NavHost, wenn Benutzer durch Ihre App navigieren. \end{itemize} -Sobald der Nutzer innerhalb der App navigiert, wird das entsprechende Fragment der Ansicht im \texttt{NavHost} dargestellt. Dabei stellt Navigationskomponente auch eine konsistente und vorhersehbare Benutzererfahrung sicher, indem sie sich an einen etablierten Satz von Prinzipien hält. Beispielsweise ermöglicht die Navigation-Komponente die Einbindung der \texttt{BottomNavigationView} mit minimalem Programmieraufwand. Unterstützt wird die Navigation durch \texttt{Safe Args}\footnote{Safe Args. \url{https://developer.android.com/guide/navigation/navigation-pass-data\#Safe-args}}, einem Gradle-Plugin, das Typsicherheit beim Navigieren und Übergeben von Daten zwischen Ansichten bietet. \Cref{fig:navigation} zeigt die grafische Repräsentation der Navigation innerhalb der App, wobei Pfeile den Navigations-Fluss zwischen Ansichten darstellen. +Sobald der Nutzer innerhalb der App navigiert, wird das entsprechende Fragment der Ansicht im \texttt{NavHost} dargestellt. Dabei stellt Navigationskomponente auch eine konsistente und vorhersehbare Benutzererfahrung sicher, indem sie sich an einen etablierten Satz von Prinzipien hält. Beispielsweise ermöglicht die Navigation-Komponente die Einbindung der \texttt{BottomNavigationView} mit minimalem Programmieraufwand. Unterstützt wird die Navigation durch \texttt{Safe Args}\footnote{Safe Args. \url{https://developer.android.com/guide/navigation/navigation-pass-data\#Safe-args}}, einem Gradle-Plugin, das Typsicherheit beim Navigieren und Übergeben von Daten zwischen Ansichten bietet. \Cref{fig:navigation} zeigt einen Ausschnitt der grafischen Repräsentation der Navigation innerhalb der App, wobei Pfeile den Navigations-Fluss zwischen Ansichten darstellen. \begin{figure}[H] \includegraphics[width=1\linewidth]{navigation.png} - \caption{Die Navigation der OUTPUT-App.}\label{fig:navigation} + \caption{Ausschnitt der Navigation innerhalb der OUTPUT-App.}\label{fig:navigation} \end{figure} \subsection{Viewbindung} -Um einfacher mit den Ansichten interagieren zu können wird eine Technik names \texttt{Viewbinding}\footnote{Viewbinding. \url{https://developer.android.com/topic/libraries/view-binding}} verwendet. Durch die Aktivierung dieses Build-Features wird automatisch, für jede vorhandene XML-Layout-Datei eine Binding-Klasse erzeugt. Eine Instanz dieser Binding-Klasse enthält direkte Verweise auf alle Ansichten, die eine ID in dem entsprechenden Layout haben. Die Verwendung von Viewbinding erlaubt somit die objektorientierte Verwendung von Views und ersetzt gleichzeitig die Funktionalität der \texttt{findViewById}-Methode. In Bezug auf die in \Cref{lst:layout} gezeigte Layout-Datei ergibt sich die in \Cref{fig:viewbinding} dargestellte Nutzung. +Um einfacher mit den Ansichten interagieren zu können wird eine Technik names \texttt{Viewbinding}\footnote{Viewbinding. \url{https://developer.android.com/topic/libraries/view-binding}} verwendet. Durch die Aktivierung dieses Build-Features wird automatisch, für jede vorhandene XML-Layout-Datei eine Binding-Klasse erzeugt. Eine Instanz dieser Binding-Klasse enthält direkte Verweise auf alle Ansichten, die eine ID in dem entsprechenden Layout haben. Die Verwendung von Viewbinding erlaubt somit die objektorientierte Verwendung von Views und ersetzt gleichzeitig die Funktionalität der \texttt{findViewById}-Methode. In Bezug auf die in \Cref{lst:layout} gezeigte Layout-Datei ergibt sich die in \Cref{fig:viewbinding} dargestellte Nutzung im Quellcode. \begin{figure}[H] \includegraphics[width=1\linewidth]{viewbinding.png} - \caption{Nutzung von Viewbinding am Beispiel der \texttt{MainActivity}-Klasse aus \Cref{lst:layout}.}\label{fig:viewbinding} + \caption{Beispiel für die Nutzung von Viewbinding.}\label{fig:viewbinding} \end{figure} \subsection{Databinding} @@ -130,7 +130,7 @@ \subsection{Databinding} \end{lstlisting} +\newpage + \section{Datenfluss- und Architektur-Patterns} -\subsection{Adapter-Pattern} +Es werden verschiedene Patterns vorgestellt, die sich im Implementationskonzept wiederfinden und auch Bestandteil der zukünftigen Entwicklung sein sollen. Diese spiegeln ebenso die Prinzipien von Android wieder und sind zentraler Bestandteil der App. + +\subsection{View-Model-ViewModel-Pattern} + +\textbf{Model-View-ViewModel (MVVM)} ist eine Variante des bekannten Model-View-Presenter (MVP) Entwurfsmusters. Das Ziel dieses Architektur-Patterns ist die Trennung von Darstellung und Logik der Benutzeroberfläche. Die Bestandteile des Patterns sind: + +\begin{itemize} + \item \textbf{Model:} Eine Instanz welche die Daten der Anwendungsdomäne enthält. Diese Objekte haben keinen direkten Zusammenhang zur View, sondern repräsentieren Datenbank-Objekte im Kontext der Anwendung. + \item \textbf{View:} Die Repräsentation einer Ansicht, ohne jegliche Anwendungslogik. + \item \textbf{ViewModel:} Die Schnittstelle zwischen den Daten im Anwendungskontext und der Repräsentation. Viewmodels stellen die Daten der Models als Datenfluss für die View bereit. +\end{itemize} + +\Cref{fig:mvvm} zeigt den Aufbau des MVVM-Patterns. Bekannte CRUD-Operationen auf den Daten werden dabei durch das Viewmodel ausgeführt. In den meisten Fällen verfügt das Model über Mechanismen um gezielt auf Änderungen der Daten reagieren zu können. Die Daten können anschließend vom ViewModel als Datenfluss für die View bereitgestellt werden. View und ViewModel verfügen über eine unidirektionale oder bidirektionale Bindung, bei welcher die View die Daten sowie Methoden des Viewmodels referenziert. Gleichzeitig kann ein gegebenes ViewModel für mehrere Views eingesetzt werden. + +\begin{figure}[H] + \includegraphics[width=1\linewidth]{mvvm.png} + \caption{Aufbau des Model-View-ViewModel-Pattern.}\label{fig:mvvm} +\end{figure} -\subsection{View-Model-Viewmodel-Pattern} +\newpage \subsection{Observer-Pattern} -\subsection{Eventbasierte Datenflüsse} \ No newline at end of file +Das \textbf{Observer-Pattern} ist ein weiteres Entwurfsmuster, welches in der Android-Entwicklung eine zentrale Rolle spielt. Es gehört zur Kategorie der Verhaltensmuster und dient zur Weitergabe von Änderungen an abhängige Datenstrukturen. Damit lassen sich Ereignis-basierte Abläufe programmieren. In der für die Android-Entwicklung üblichen Variante des Observer-Patterns, informiert ein Objekt (genannt \texttt{Subjekt}) alle abhängigen Objekte (genannt \texttt{Observer}) von Änderungen und überträgt dabei jeweils eine aktuelle Kopie der Daten als Parameter. Der Ablauf ist in \Cref{fig:observer} gezeigt. Diese Form wird auch \texttt{Push-Update Observer} genannt. + +\begin{figure}[H] + \includegraphics[width=0.65\linewidth]{observer.png} + \caption{Aufbau des Observer-Pattern.}\label{fig:observer} +\end{figure} \ No newline at end of file diff --git a/sections/03_analysis.tex b/sections/03_analysis.tex index 278a69a..ddf86ed 100644 --- a/sections/03_analysis.tex +++ b/sections/03_analysis.tex @@ -1 +1,33 @@ -\chapter{Analyse}\label{ch:analyse} \ No newline at end of file +\chapter{Analyse}\label{ch:analyse} + +Um ein konkretes Lösungskonzept zu entwickeln, musste die bestehende App zunächst analysiert werden. Im Folgenden werden die verschiedenen Aspekte dieser Phase erläutert, um anschließend in \Cref{ch:konzept} die konkreten Lösungskonzepte vorzustellen. + +\section{Struktur des Couchbase-Datenbank-Frameworks} + +Für die Persistierung von Daten bieten sich eine Vielzahl von Möglichkeiten. Während sich kleinere Datenmengen (< 1.42 MB) für nutzerbezogene Daten bereits in den \texttt{SharedPreferences}\footnote{SharedPreferences. \url{https://developer.android.com/reference/android/content/SharedPreferences}} speichern lassen, so bietet die Android-Platform mit \texttt{Room}\footnote{Room. \url{https://developer.android.com/training/data-storage/room}} eine umfängliche Bibliothek zur Erstellung von SQLite-Datenbanken. Eine Funktionalität die beiden Implementationen allerdings fehlt, ist die Synchronisierung mit einem Remote-Server. Zeitgleich sollten die Daten lokal persistiert werden, um die App auch ohne Internetzugriff vollständig bedienen zu können. Aus diesen Anforderungen ergeben sich nur eine geringe Anzahl an Frameworks, die für die Nutzung im Rahmen der OUTPUT-App zutreffend sind. Da die Nutzungskonditionen des Dienstes Realm starke Limitationen aufweisen, fiel die Entscheidung zukünftig stattdessen das Framework Couchbase verwenden zu wollen. Aus diesem Grund wurden im Verlauf des Sommersemesters 2020 Datenbank-Frameworks erstellt, welche die Bereitstellung von Daten für die App sowie die notwendige Synchronisationsfunktion beinhalten. Um die Komplexität des Couchbase-Frameworks zu Kapseln abstrahieren die Bibliotheken Zugriffe auf die Dokumente sowie Serialisierung und Deserialisierung von Daten und stellen den jeweiligen Apps damit eine Schnittstelle für den Datenzugriff zur Verfügung. Die zentrale Idee hinter der Umsetzung bildete das Repository-Pattern. Dabei stehen verfügbaren Operationen zum Erstellen, Lesen, Schreiben und Löschen von Daten zur Verfügung, während die zugrunde liegende Implementierung des Couchbase-Frameworks versteckt wird. Diese Metastruktur des Frameworks ist in \Cref{fig:metaframework} gezeigt. + +\begin{figure}[H] + \includegraphics[width=1\linewidth]{metaframework.pdf} + \vspace{-25mm} + \caption{Bereitstellung einer Bibliothek für die Abstraktion von Datenbank-Operationen mittels Couchbase.}\label{fig:metaframework} +\end{figure} + + +Um die in Dokumenten abgelegten Daten in ein objektorientiertes Schema überführen zu können, entschieden wir uns einen sogenannten +\texttt{DocumentIdentifier} hinzuzufügen. Diese Zeichenkette wird als Teil des Serialisierungsprozess im Dokument gespeichert und dient im folgenden zur Abgrenzung einzelner Modell-Klassen. Damit lassen sich Objekte eines bestimmten Typs von der Datenbank lesen um bspw. einen Veranstaltungsplan zu erzeugen. Des Weiteren wird die Eigenschaft des (zusammengesetzten) Primärschlüssel über eine Annotation im Quellcode angegeben, wodurch Objekte eindeutig identifizierbar sind. Ähnlich des Primärschlüssels können einzelne Attribute auch mittels Annotation für die Volltextsuche markiert werden, um bestimmte Schlagwörter in Texten zu finden. Mittels generischer Programmierung konnten wir erreiche, dass sämtliche Operationen durch einmalige Definition in der Basisklasse Repository anschließend für alle Modelle entsprechende Methoden bereitstellt, welche die notwendigen Typen automatisch inferieren kann. Somit genügen wenige Zeilen, um neue Modelle in die bestehende Repository-Architektur hinzuzufügen. Die Struktur ist in \Cref{fig:generic} gezeigt. Außerdem ist es möglich asynchrone Programmierpraktiken einzubinden, bei welchen Funktionsaufrufe in Kotlin Coroutines ausgeführt werden können. + +\begin{figure}[H] + \includegraphics[width=0.85\linewidth]{generic.pdf} + \caption{Generisches Konzept zur Umsetzung des Repository-Patterns für Model-Klassen.}\label{fig:generic} +\end{figure} + +\section{Ermittlung einer Dialoglandkarte} + +Da die Android-App in ihrer Fassung ohne weiteres abstürzte und in sich in keinem nutzbaren Zustand befand, wurde die bestehende iOS-App analysiert. Ziel dieser Arbeit war es, eine Dialoglandkarte zu erstellen, anhand welcher die Navigationswege eines Nutzers in der App nachvollzogen werden konnte. Gleichzeitig sollte die erstellte Übersicht eine topologische Ordnung der Ansichten bieten und die genutzten UI-Elemente aufzeigen. Die in \Cref{fig:mindmap} abgebildete Dialoglandkarte beinhaltet bereits eine Gruppierung von Ansichten in eigenständige Teilbereiche der App, die für die nachfolgende Implementierung in separaten Komponenten nützlich war. Durch die Pfeile zwischen Ansichten konnten die Daten- und Navigationsflüsse innerhalb der App aufbereitet werden. + +\begin{figure}[H] + \includegraphics[width=1\linewidth]{mindmap.pdf} + \caption{Die Dialoglandkarte zur vorangegangenen Version der iOS App zeigt die Navigationswege innerhalb der App, sowie die genutzten UI-Elemente.}\label{fig:mindmap} +\end{figure} + + diff --git a/viewbinding.png b/viewbinding.png deleted file mode 100644 index 2ffeaaf..0000000 Binary files a/viewbinding.png and /dev/null differ