Add Kotlin source code formatting
This commit is contained in:
parent
dade003d84
commit
089df551a7
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
% Code
|
% Code
|
||||||
\usepackage{listings}
|
\usepackage{listings}
|
||||||
|
\usepackage{color}
|
||||||
\definecolor{dkgreen}{rgb}{0,0.6,0}
|
\definecolor{dkgreen}{rgb}{0,0.6,0}
|
||||||
\definecolor{gray}{rgb}{0.5,0.5,0.5}
|
\definecolor{gray}{rgb}{0.5,0.5,0.5}
|
||||||
\definecolor{mauve}{rgb}{0.58,0,0.82}
|
\definecolor{mauve}{rgb}{0.58,0,0.82}
|
||||||
@ -80,6 +81,22 @@
|
|||||||
morestring=[b]',
|
morestring=[b]',
|
||||||
morestring=[b]",
|
morestring=[b]",
|
||||||
}
|
}
|
||||||
|
\lstdefinelanguage{Kotlin}{
|
||||||
|
comment=[l]{//},
|
||||||
|
commentstyle={\color{gray}\ttfamily},
|
||||||
|
emph={delegate, filter, first, firstOrNull, forEach, lazy, map, mapNotNull, println, return@},
|
||||||
|
emphstyle={\color{mauve}},
|
||||||
|
identifierstyle=\color{black},
|
||||||
|
keywords={abstract, actual, as, as?, break, by, class, companion, continue, data, do, dynamic, else, enum, expect, false, final, for, fun, get, if, import, in, interface, internal, is, null, object, override, package, private, public, return, set, super, suspend, this, throw, true, try, typealias, val, var, vararg, when, where, while},
|
||||||
|
keywordstyle={\color{blue}\bfseries},
|
||||||
|
morecomment=[s]{/*}{*/},
|
||||||
|
morestring=[b]",
|
||||||
|
morestring=[s]{"""*}{*"""},
|
||||||
|
ndkeywords={@Deprecated, @JvmField, @JvmName, @JvmOverloads, @JvmStatic, @JvmSynthetic, Array, Byte, Double, Float, Int, Integer, Iterable, Long, Runnable, Short, String},
|
||||||
|
ndkeywordstyle={\color{orange}\bfseries},
|
||||||
|
sensitive=true,
|
||||||
|
stringstyle={\color{dkgreen}\ttfamily},
|
||||||
|
}
|
||||||
|
|
||||||
\usepackage{setspace}
|
\usepackage{setspace}
|
||||||
\setstretch{1.2} %Zeilenabstand
|
\setstretch{1.2} %Zeilenabstand
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
\subsection{Authentifizierung}
|
\subsection{Authentifizierung}
|
||||||
Zur Authentifizierung benutzen wir JWT, welches bei jeder Anfrage ans Backend mit geschickt werden muss. Das Token erhält man beim Einloggen mit den richtigen Daten und muss persistiert werden, bis sich der Benutzer ausloggt. Dazu speichere ich das Token im privaten Speicher der App. In allen weiteren Activities kann dann auf den Speicher zugegriffen werden und das Token beim Erstellen des \verb|AuthenticationInterceptor|s mitgegeben werden. Beim Ausloggen wird einfach die Datei mit dem Token aus dem Speicher gelöscht. \\
|
Zur Authentifizierung benutzen wir JWT, welches bei jeder Anfrage ans Backend mit geschickt werden muss. Das Token erhält man beim Einloggen mit den richtigen Daten und muss persistiert werden, bis sich der Benutzer ausloggt. Dazu speichere ich das Token im privaten Speicher der App. In allen weiteren Activities kann dann auf den Speicher zugegriffen werden und das Token beim Erstellen des \verb|AuthenticationInterceptor|s mitgegeben werden. Beim Ausloggen wird einfach die Datei mit dem Token aus dem Speicher gelöscht. \\
|
||||||
Der \verb|AuthenticationInterceptor| ist Kind von der \verb|Interceptor|-Klasse aus der \verb|okhttp3|-Bibliothek, welche in Retrofit eingebunden ist. Mithilfe des Interceptors können REST-Abfragen Header-Daten mitgegeben werden. In unserem Fall ist das das \verb|Authorization|-Feld mit dem Token.
|
Der \verb|AuthenticationInterceptor| ist Kind von der \verb|Interceptor|-Klasse aus der \verb|okhttp3|-Bibliothek, welche in Retrofit eingebunden ist. Mithilfe des Interceptors können REST-Abfragen Header-Daten mitgegeben werden. In unserem Fall ist das das \verb|Authorization|-Feld mit dem Token.
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}[language=Kotlin]
|
||||||
class AuthenticationInterceptor(pToken: String) : Interceptor {
|
class AuthenticationInterceptor(pToken: String) : Interceptor {
|
||||||
private val token = pToken
|
private val token = pToken
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
@ -67,7 +67,7 @@
|
|||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Der Interceptor wird dem HTTP-Client hinzugefügt, welcher später bei der Erzeugung des Retrofit-Builders notwendig ist.
|
Der Interceptor wird dem HTTP-Client hinzugefügt, welcher später bei der Erzeugung des Retrofit-Builders notwendig ist.
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}[language=Kotlin]
|
||||||
val httpClient = OkHttpClient.Builder()
|
val httpClient = OkHttpClient.Builder()
|
||||||
val interceptor = AuthenticationInterceptor(token)
|
val interceptor = AuthenticationInterceptor(token)
|
||||||
httpClient.addInterceptor(interceptor)
|
httpClient.addInterceptor(interceptor)
|
||||||
@ -75,7 +75,7 @@
|
|||||||
|
|
||||||
\subsection{Anzeige der Daten in der Main Activity}\label{subsec:AnzeigeDaten}
|
\subsection{Anzeige der Daten in der Main Activity}\label{subsec:AnzeigeDaten}
|
||||||
Die Daten werden per REST-Aufruf mithilfe vom Retrofit-Framework vom Backend geholt. Um Anfragen zusenden benötigt man einen Retrofit-Builder. Diesem wird die anzufragende URL, ein JSON-Konverter und ein HTTP-Client mitgegeben. Aus diesem Builder und einer Service-Klasse, in der die Methoden definiert sind, wird ein Objekt erzeugt mit dem die Methoden aufrufbar sind.
|
Die Daten werden per REST-Aufruf mithilfe vom Retrofit-Framework vom Backend geholt. Um Anfragen zusenden benötigt man einen Retrofit-Builder. Diesem wird die anzufragende URL, ein JSON-Konverter und ein HTTP-Client mitgegeben. Aus diesem Builder und einer Service-Klasse, in der die Methoden definiert sind, wird ein Objekt erzeugt mit dem die Methoden aufrufbar sind.
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}[language=Kotlin]
|
||||||
val builder = Retrofit.Builder()
|
val builder = Retrofit.Builder()
|
||||||
.baseUrl("http://plesk.icaotix.de:5000")
|
.baseUrl("http://plesk.icaotix.de:5000")
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
@ -84,7 +84,7 @@
|
|||||||
service = retrofit.create(GeofenceService::class.java)
|
service = retrofit.create(GeofenceService::class.java)
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Die Klasse \verb|GeofenceService| dient, wie oben beschrieben, zur definition der Endpunkte in From von Methodenaufrufen. Dort wird definiert, ob es ein \verb|POST| oder \verb|GET| Entpunkt ist, wie der Pfad lautet und was für Parameter mitgegeben werden.
|
Die Klasse \verb|GeofenceService| dient, wie oben beschrieben, zur definition der Endpunkte in From von Methodenaufrufen. Dort wird definiert, ob es ein \verb|POST| oder \verb|GET| Entpunkt ist, wie der Pfad lautet und was für Parameter mitgegeben werden.
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}[language=Kotlin]
|
||||||
@POST("/login")
|
@POST("/login")
|
||||||
fun login(@Body login_data: ValuesUserLogin): Call<Void>
|
fun login(@Body login_data: ValuesUserLogin): Call<Void>
|
||||||
|
|
||||||
@ -95,14 +95,14 @@
|
|||||||
fun getAccounts(@Query("username") username : String): Call<EmbeddedAccounts>
|
fun getAccounts(@Query("username") username : String): Call<EmbeddedAccounts>
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Der Rückgabewert der Methoden ist immer vom Typ \verb|Call|. Wenn aus dem Body Werte gelesen werden sollen, muss eine Art Skelett-Klasse angelegt werden mit den relevanten Feldern. Die Klasse \verb|ValuesUser| stellt Werte der Antwort bereit, wie z. B. den Vornamen.
|
Der Rückgabewert der Methoden ist immer vom Typ \verb|Call|. Wenn aus dem Body Werte gelesen werden sollen, muss eine Art Skelett-Klasse angelegt werden mit den relevanten Feldern. Die Klasse \verb|ValuesUser| stellt Werte der Antwort bereit, wie z. B. den Vornamen.
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}[language=Kotlin]
|
||||||
class ValuesUser(firstname: String) {
|
class ValuesUser(firstname: String) {
|
||||||
@SerializedName("firstname")
|
@SerializedName("firstname")
|
||||||
var firstname = firstname
|
var firstname = firstname
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Der Aufruf der Methode erfolgt Asynchron. Deshalb darf sich nicht auf das Ergebnis des Aufrufs direkt danach verlassen werden, sonst bekommt man eine Null-Pointer-Excetion. Die Methode \verb|enqueue| besitzt ein Callback-Objekt als Parameter, welches \verb|onResponse| und \verb|onFailure| überschreibt. Dort wird entsprechend definiert was in den jeweiligen Fällen ausgeführt werden soll.
|
Der Aufruf der Methode erfolgt Asynchron. Deshalb darf sich nicht auf das Ergebnis des Aufrufs direkt danach verlassen werden, sonst bekommt man eine Null-Pointer-Excetion. Die Methode \verb|enqueue| besitzt ein Callback-Objekt als Parameter, welches \verb|onResponse| und \verb|onFailure| überschreibt. Dort wird entsprechend definiert was in den jeweiligen Fällen ausgeführt werden soll.
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}[language=Kotlin]
|
||||||
val call = service.getUser()
|
val call = service.getUser()
|
||||||
call.enqueue(object : Callback<ValuesUser> {
|
call.enqueue(object : Callback<ValuesUser> {
|
||||||
override fun onResponse(call: Call<ValuesUser>, response: Response<ValuesUser>) {
|
override fun onResponse(call: Call<ValuesUser>, response: Response<ValuesUser>) {
|
||||||
@ -133,7 +133,7 @@
|
|||||||
Die Geofencing-Funktion ist die zentrale Funktion für die App und auch für das gesamte Projekt. Deshalb war es wichtig, dass sie frühzeitig funktioniert. \\
|
Die Geofencing-Funktion ist die zentrale Funktion für die App und auch für das gesamte Projekt. Deshalb war es wichtig, dass sie frühzeitig funktioniert. \\
|
||||||
Um die Positon eines Gerätes zu bestimmen bedarf es einer Berechtigung, die vom Benutzer bestätigt werden muss. Für Geräte mit API-Level 28 und niedriger muss dafür die \verb|ACCESS_FINE_LOCATION|-Berechtigung gesetzt werden und für API-Level 29 und höher \verb|ACCESS_BACKGROUND_LOCATION|. \\
|
Um die Positon eines Gerätes zu bestimmen bedarf es einer Berechtigung, die vom Benutzer bestätigt werden muss. Für Geräte mit API-Level 28 und niedriger muss dafür die \verb|ACCESS_FINE_LOCATION|-Berechtigung gesetzt werden und für API-Level 29 und höher \verb|ACCESS_BACKGROUND_LOCATION|. \\
|
||||||
Der Geofence wird initialisiert, wenn für den Benutzer Geo-Daten gespeichert sind. Ist dies der Fall, so wird ein \verb|GeofencingClient| angelegt, dem dann der Geofence hinzugefügt wird. Der Geofence wird erzeugt mit den Parametern: Breitengrad, Längengrad, Radius, der Lebenszeit des Fence und den Übergangstypen. Die Typen sind in unserem Fall \verb|GEOFENCE_TRANSITION_ENTER| und \verb|GEOFENCE_TRANSITION_EXIT|, da wir immer reagieren wollen, wenn der Nutzer den Bereich verlässt oder betritt.
|
Der Geofence wird initialisiert, wenn für den Benutzer Geo-Daten gespeichert sind. Ist dies der Fall, so wird ein \verb|GeofencingClient| angelegt, dem dann der Geofence hinzugefügt wird. Der Geofence wird erzeugt mit den Parametern: Breitengrad, Längengrad, Radius, der Lebenszeit des Fence und den Übergangstypen. Die Typen sind in unserem Fall \verb|GEOFENCE_TRANSITION_ENTER| und \verb|GEOFENCE_TRANSITION_EXIT|, da wir immer reagieren wollen, wenn der Nutzer den Bereich verlässt oder betritt.
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}[language=Kotlin]
|
||||||
geofencingClient = LocationServices.getGeofencingClient(this)
|
geofencingClient = LocationServices.getGeofencingClient(this)
|
||||||
geofence = Geofence.Builder().setRequestId("Geofence")
|
geofence = Geofence.Builder().setRequestId("Geofence")
|
||||||
.setCircularRegion(lat, long, rad)
|
.setCircularRegion(lat, long, rad)
|
||||||
@ -142,14 +142,14 @@
|
|||||||
.build()
|
.build()
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Um den Geofence-Client zu starten wird auf das Objekt die \verb|addGeofences|-Methode ausgeführt mit einem \verb|GeofencingRequest|-Objekt und einem \verb|PendingIntent|-Objekt als Parameter.
|
Um den Geofence-Client zu starten wird auf das Objekt die \verb|addGeofences|-Methode ausgeführt mit einem \verb|GeofencingRequest|-Objekt und einem \verb|PendingIntent|-Objekt als Parameter.
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}[language=Kotlin]
|
||||||
geofencingClient.addGeofences(getGeofencingRequest(), geofencePendingIntent)?.run {
|
geofencingClient.addGeofences(getGeofencingRequest(), geofencePendingIntent)?.run {
|
||||||
addOnSuccessListener { ... }
|
addOnSuccessListener { ... }
|
||||||
addOnFailureListener { ... }
|
addOnFailureListener { ... }
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
In der \verb|getGeofencingRequest|-Methode wird festgelegt auf welches initiale Event reagiert werden soll und der oben erstellte Geofence wird hinzugefügt. Als initiales Event habe ich \verb|INITIAL_TRIGGER_ENTER| gewählt, da es ausgelöst wird wenn man sich bereits im Bereich befindet und die App startet. Denn erst mit dem Eintrittsevent wird der Button zum Starten der Aufzeichnung freigeschaltet. Das \verb|geofencePendingIntent| definiert die BroadcastReceiver-Klasse, welche bei jedem Event aufgerufen wird.
|
In der \verb|getGeofencingRequest|-Methode wird festgelegt auf welches initiale Event reagiert werden soll und der oben erstellte Geofence wird hinzugefügt. Als initiales Event habe ich \verb|INITIAL_TRIGGER_ENTER| gewählt, da es ausgelöst wird wenn man sich bereits im Bereich befindet und die App startet. Denn erst mit dem Eintrittsevent wird der Button zum Starten der Aufzeichnung freigeschaltet. Das \verb|geofencePendingIntent| definiert die BroadcastReceiver-Klasse, welche bei jedem Event aufgerufen wird.
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}[language=Kotlin]
|
||||||
private fun getGeofencingRequest(): GeofencingRequest {
|
private fun getGeofencingRequest(): GeofencingRequest {
|
||||||
return GeofencingRequest.Builder().apply {
|
return GeofencingRequest.Builder().apply {
|
||||||
setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
|
setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
|
||||||
@ -163,7 +163,7 @@
|
|||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Die \verb|GeofenceBroadcastReceiver|-Klasse definiert was bei den jeweiligen Events ausgeführt werden soll. In unserem Fall ist dies das Verändern einer boolean Shared-Prefrences-Variable, je nachdem ob der Bereich betreten oder verlassen wurde. Warum diese Art und Weise gewählt wurde lesen Sie in Kapitel \ref{sec:Probleme}.\\
|
Die \verb|GeofenceBroadcastReceiver|-Klasse definiert was bei den jeweiligen Events ausgeführt werden soll. In unserem Fall ist dies das Verändern einer boolean Shared-Prefrences-Variable, je nachdem ob der Bereich betreten oder verlassen wurde. Warum diese Art und Weise gewählt wurde lesen Sie in Kapitel \ref{sec:Probleme}.\\
|
||||||
Das Code-Beispiel zeigt die Aktion beim Betreten des Bereichs.
|
Das Code-Beispiel zeigt die Aktion beim Betreten des Bereichs.
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}[language=Kotlin][language=Kotlin]
|
||||||
context!!.getSharedPreferences("LOCATION", Context.MODE_PRIVATE)
|
context!!.getSharedPreferences("LOCATION", Context.MODE_PRIVATE)
|
||||||
?.edit()
|
?.edit()
|
||||||
?.putBoolean("ENABLED", true)
|
?.putBoolean("ENABLED", true)
|
||||||
|
Loading…
Reference in New Issue
Block a user