Add Provider

pull/3/head
Jonas Franz 3 years ago
parent 4f4e3bd160
commit bd266519eb
  1. 36
      bibliography.bib
  2. 47
      chapters/basics/state-management.tex

@ -122,13 +122,23 @@ isbn="978-981-15-1465-4"
urldate = {2022-01-23},
}
@phdthesis{Faust,
type = {Bachelor Thesis},
author = {Sebastian Faust},
title = {Using Google´s Flutter Framework for the Development of a Large-Scale Reference Application},
url = {https://nbn-resolving.org/urn:nbn:de:hbz:832-epub4-14989},
pages = {85},
language = {en}
@Misc{changeNotifier,
author = {{Google LLC}},
title = {ChangeNotifier class - foundation library - Dart API},
year = {2021},
url = {https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html},
urldate = {2022-01-27},
}
@PhdThesis{Faust,
author = {Sebastian Faust},
school = {Technische Hochschule Köln},
title = {Using Google´s Flutter Framework for the Development of a Large-Scale Reference Application},
year = {2020},
type = {Bachelor Thesis},
language = {en},
pages = {85},
url = {https://nbn-resolving.org/urn:nbn:de:hbz:832-epub4-14989},
}
@Conference{blocTalk,
@ -140,4 +150,16 @@ isbn="978-981-15-1465-4"
urldate = {2022-01-23},
}
@PhdThesis{stateManagementThesis,
author = {Dmitrii Slepnev},
school = {South-Eastern Finland University of Applied Sciences},
title = {State management approaches in Flutter},
year = {2020},
type = {Bachelor Thesis},
language = {en},
url = {https://nbn-resolving.org/urn:nbn:de:hbz:832-epub4-14989},
}
@Comment{jabref-meta: databaseType:bibtex;}

@ -44,6 +44,7 @@ Wie vorausgehend beschrieben, muss ein Zustandsverwaltungssystem aber nicht nur
Anschaulich lässt sich dies durch das Beispiel \autoref{fig:flutterTreeSetState} darstellen, welches eine Anwendung, die global speichern muss, welche Person aktuell angemeldet ist, zeigt. Da diese Information in diesem Beispiel an diversen Stellen innerhalb der Anwendung benötigt wird, macht es Sinn, diese Information weit oben im Baum in Form eines \texttt{StatefulWidget} namens \texttt{LoginStateWidget} zu speichern, da der Datenfluss innerhalb des Baums ausschließlich unidirektional von oben nach unten stattfindet. Um diese Information nun an die Widgets zu kommunizieren, die es benötigen - in diesem Fall \texttt{InformationConsumer} - muss \texttt{LoginStateWidget} die Information per Konstruktor an das nachgelagerte Widget weitergeben. Diese nachgelagerten Widgets (\texttt{A, B, C}) müssen dies ebenfalls tun, bis die Information am Ziel \texttt{InformationConsumer} angekommen ist. Diese Anwendungsmuster wird in der Literatur als \blockquote[{\cite[Kap.8.2]{flutterinaction}}]{lifting state up} bezeichnet.
 \subsubsection{InheritedWidget}
\label{sec:inheritedWidget}
Neben der Möglichkeit, den Zustand über den Widget-Baum nach unten weiter zu propagieren, bietet Flutter noch das Konzept \texttt{InheritedWidget} an. Diese Widgets bilden eine eigene Widget-Gruppe und sind weder den \texttt{StatefulWidgets} noch den \texttt{StatelessWidgets} zuzuordnen. \autocite[Kap.8.2.1]{flutterinaction} \texttt{InheritedWidgets} ermöglichen es nachgeordneten Widgets, auf den Zustand des Widgets direkt zuzugreifen. Hier muss allerdings beachtet werden, dass das \texttt{InheritedWidget} immer unveränderlich ist. Dies bedeutet, dass andere Widgets über die Veränderung von Konstruktor-Parametern neue Instanzen des Widgets erstellen müssen, um eine Zustandsänderung zu bewirken. Daher lassen sich diese Widgets oft in Kombination mit \texttt{StatefulWidgets}, welche für die Manipulation des Zustands zuständig sind, vorfinden.
@ -79,6 +80,7 @@ Dieser Mechanismus wird auch von diversen anderen Zustandsverwaltungssystemen ve
Als Erweiterung des \texttt{InheritedWidget} kann man \texttt{InheritedModel} sehen. Dabei ist die Funktionsweise äquivalent mit einer Besonderheit. Es besteht hier nämlich die Möglichkeit Zugriffe und Änderungen nach sogenannten \texttt{aspects} zu kategorisieren. Somit kann bei komplexeren Zuständen es ermöglicht werden, dass Widgets nur dann neugebaut werden, wenn der betreffende \text{aspect} sich ändert. \autocite{inheritedModel}
\subsection{Business Logic Components (BLoC)}
\label{sec:bloc}
Das 2018 auf der Entwicklerkonferenz DartConf vorgestellte \ac{bloc}-Pattern ist im Vergleich zu den bisher vorgestellten Ansätzen ein Design-Pattern zur Verwaltung von Zuständen und nicht nur ein Werkzeug des Frameworks. Das Ziel von \ac{bloc} ist es, die komplette Logik von der Benutzeroberfläche zu trennen. \autocite[S.17]{Faust} Die Logik und der Zustand wird dabei in den namensgebenden \acf{bloc} verwaltet. Die Komponenten haben die Aufgabe, Zustands-Ereignisse von Widgets zu empfange und Widgets zu aktualisieren, wenn sich der Zustand ändert. Diese Komponenten unterliegen grundlegenden, nicht-verhandelbaren Regeln, welche im Vortrag von \citeauthor{blocTalk} definiert worden sind:
@ -102,6 +104,51 @@ Jede Seite (engl. Screen) sollte dabei exakt einem \ac{bloc} zugeordnet sein. Da
\subsection{Provider}
Provider ist eine Bibliothek, die auf dem \texttt{InheritedWidget}-Ansatz (siehe \autoref{sec:inheritedWidget}) beruht. Dabei vereinfacht die Bibliothek die Benutzung und Erstellung von Klassen, die Zustände verwalten, und kombiniert das \texttt{InheritedWidget}-Konzept unter anderem mit der \texttt{ChangeNotifer}-Klasse. \autocite{stateManagementThesis}
Die abstrakte Klasse \texttt{ChangeNotifier} bietet die Möglichkeit Event-Listener für die erbende Klasse zu registrieren und bei Veränderung über den Aufruf einer entsprechenden Methode diese zu benachrichtigen, wie in \autoref{lst:providerStore} in der Methode \texttt{updateUser} gezeigt wird. \autocite{changeNotifier} Diese Kombinationsmöglichkeit wird auch für andere Konzepte und Klassen angeboten. So lassen sich Provider mit \texttt{Listnables}, also Objekte, die Events emittieren können, \texttt{ValueListanble}, also \texttt{Listnables}, die nur über Änderungen einer Variable benachrichtigen, \texttt{Streams}, welche bereits in \autoref{sec:bloc} vorgestellt worden sind oder \texttt{Futures} kombinieren.
\begin{lstlisting}[caption={Aufbau einer ChangeNotifier-Klasse für Provider}, label={lst:providerStore}]
class UserStore extends ChangeNotifier {
var user;
UserStore(this.user);
void updateUser(newUser) {
this.user = newUser;
notifyListeners();
}
}
\end{lstlisting}
Also kann festgehalten werden, dass Provider im ersten Schritt eine Form von \textit{Dependency Injection} zur Verfügung stellt und im zweiten Schritt mit einer Klasse verknüpft wird, welche über Änderungen informiert, und somit zu einer Zustandsverwaltungslösung ausgebaut werden kann.
\begin{lstlisting}[caption={Injektion und Abruf von Provider-Klassen}, label={lst:providerExample}]
class ProvidingWidget extends StatelessWidget {
final user;
const ProvidingWidget({Key? key, this.user}) : super(key: key);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(create: (context) => UserStore(user), child: ConsumingWidget());
}
}
class ConsumingWidget extends StatelessWidget {
const ConsumingWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final user = Provider.of<UserStore>(context).user;
return Text(user.firstName);
}
}
\end{lstlisting}
Um eine \texttt{ChangeNotifier} als Zustandsverwaltungslösung mit Provider zu nutzen, ist es bei Provider erforderlich, die jeweiligen Zustands-Klassen (oft Store genannt) in den Widget-Baum zu integrieren. Dies erfolgt wie in der Klasse \texttt{ProvidingWidget} in \autoref{lst:providerExample} gezeigt, durch das Erstellen eines Widgets, welche keine eigene Benutzeroberfläche darstellen, sondern nur Widgets \blockquote{nach unten} durchreichen. Nun können die Daten aus der Zustands-Klasse von allen Widget abgerufen werden, die sich im Widget-Baum an einen der nachgelagerten Äste der injizierenden Widgets befindet.
Die nachgelagerten Widgets können dabei, die Zustands-Klasse durch eine einfachen, generischen Methodenaufruf der Provider-Bibliothek abrufen. Durch die Verwendung von \texttt{InheritedWidget} innerhalb der Bibliothek wird damit sichergestellt, dass wenn sich Daten in den Zustands-Klassen ändern, referenzierende Widgets über diese Änderung informiert werden und gegebenenfalls neu gebaut werden.
\subsection{Riverpod}
\subsection{Redux}

Loading…
Cancel
Save