Home
Linux
Flutter
Widget / RenderObject / Lifecycle
Widget
- levný na výrobu
- při každém zavolání build metody se vlastně zahodí a vytvoří nový
- je immutable
- paralelně k widget tree existuje strom elementů a
RenderObject
ů - drží jen konfiguraci widgetu
Element
- mutable
- reprezentuje aktuální instanci widgetu
- handluje life cycle widgetu a jeho závislosti ve stromu - kdo je parent, kdo je child
- udržuje si referenci na aktuální widget a zároveň referenci na render object, který ma taky svůj strom
- instance je pak buď
StatelessElement
neboStatefullElement
- při
build
metodě se volácanUpdate
metoda, ktera zjišťuje jestli starý a nový widget mají stejný runtime typ a klíč (není-li klíč tak jen typ -> pokud jsou shodné tak není třeba zahazovat instanci Elementu a jen up datovat property -> je přece mutable -> tak samo se nezahodí render object -> úspora výkonu
RenderObject
- zodpovědný za kreslení na convos
Best practices
- části stromu, kde se odehrávají setState změny je nejlépe zabalit do custom widgetu a volat změny tam -> zmenší se scope setState a musí se updatovat menší část stromu
- taktéž lepší custom widget než metoda tvořící strukturu widgetů -> stále patří do velkého scopu nadřazeného widgetu a updatují větší celek
- Inherited Widget - vyvolává se přes statickou metodu get typicky
-
MediaQuery.of(context)
-
Provider.of(content)
-
toto volání nejen, že najde příslušný
InheritedWidget
ale zároveň zařadí volající widget do seznamu subsriberů, takže kdykoliv se v InheritedWidget změní stav, tak vyvolá rebuild i subsribovaných widgetů -> subsription dělat co nejníže ve stromu co to jde -> nebo vymezit jen oblast zájmu pokud to jeInheritedModel
, e.g.MediaQuery.sizeof(context)
bude notifikovat jen při změně size propert
-
State lifecycle
stateDiagram-v2 initState --> didChangeDependencies didUpdateWidget --> build didChangeDependencies --> build setState --> build build --> dispose note left of initState pouze jednou při mountování do stromu end note note left of didUpdateWidget při změně Widgetu end note note left of dispose při odstranění Ze stromu end note note left of didChangeDependencies při změně InheritedWidgetů na které jsme referencovali end note
- v did metotách nevolat
setState
, zbytečně to duplikuje volání build metody dispose
musí uvolnit veškeré resourcy jako controllery, listenery, stream subscribery, jinak je garbage collector neuvolní a dojde k memory leakuconst
třídy se stejnými argumenty budou mít v paměti pouze jednu instanci =>const
widget nevyvolá rebuild sebe a celého svého podstromu- totéž platí pokud je widget ve state třídě uložen jako final properta => odkazuje na stejné místo v paměti a framework widget ze stejné paměti nerebuilduje
repaintBoundary
může obalit widget a říctRenderObjectu
aby nešiřilneedRepaint
flag příliš dalekoListy
nejlépe přesitemBuilder
ashrinkWrap = false
, jinak rozbíjí 1azy loading => donutí vypočítat rozměry všech položekcacheExtent
definuje rozsah načteného obsahuitemBuilderu
State management
vanilla state management - pouziti nastroju, ktere dodava ciste framework bez pouziti reseni tretich stran
- ephemeral state - docasny stav, ktery neprezije restart aplikace, byva lokalni k danemu widgetu, nikam se neuklada
- application state - stav trvalejsiho razu, pres vice screen nebo widgetu, muze se ulozit a obnovit po restartu aplikace
Lifting up
- komponenty musi sdilet nejaky stav/data (vice widgetu nebo screen)
- je mozne instanci stavu presunout do state objektu jejich sdileneho parenta
- vysledkem byva tesna zavislost (coupling) se spoustou vzajemnych callbacku predanych v konstruktoru widgetu
- neda se moc dobre skalovat a pridavanim novych podminek vznika silene komplikovany chaos
Observer pattern
- behavioralni pattern, klient se nechce cyklicky dotazovat, jestli uz nastal kyzeny stav, tak samo server(observable) nechce rozesilat info o zmene vsem komponentam v systemu (spoustu z nich by to bylo jedno)
- komponenta obsahujici zajimavy stav (observable nebo publisher) implementuje List subscriberu a metody addListener, removeListener
- v pripade zmeny stavu informuje vsechny subscribery pres dodany callback
- komponenty zavisle na tomto stavu se zaregistruji (listener nebo subscriber)
Zajimave tridy
- Listenable (abstraktni trida s addListener() a removeListener())
- ValueListenable (pridava jen hodnotu typu T a jeji getter do Listenable)
- ChangeNotifier (implementuje Listenable interface a pridava List _listeners metodu notifyListeners(), ktera notifikuje subscribery)
- ValueNotifier (implementuje ChangeNotifier s jednou observable promennou typu T, implementuje take ValueListenable
) - ValueListenableBuilder (widget, ktery zabaluje vsechno dohromady - konstruktor sezere ValueListenable
a builder, ktery vyplivne child widget) - obvykle stav obsahuje vice promennych a pak se implementuje ChangeNotifier pro kazdou cast logiky - ma vice promennych definujicich stav a v prislusnych setterech nebo metodach vyvolava notifyListeners() metodu
- widget vlastnici instanci ChangeNotifier musi na nem ve vlastnim dispose() take zavolat changeNotifier.dispose()
- ListenableBuilder (handluje za nas pridavani/odebirani subscriberu, abchom je nezapomneli na spravnych mistech pridat/odebrat), na vstupu prebira obecny Listenable typ
- zrejme sam sebe subscribuje a pokud dojde k notifikaci tak zavola na sobe setState, aby to zpropagoval do childa?
Inherited Widget
- MediaQuery, Navigator a Theme jsou InheritedWidgety, ktere vklada do stromu WidgetsApp, ktery je vracen MaterialApp nebo CupertionApp
- obsahuje
bool updateShouldNotify(covariant InheritedWidget oldWidget)
, kde muzeme porovnat stary s novym po zmene a vyhodnotit, jestli dana zmena ma byt notifikovana (true) - pri implementaci definujeme statickou metodu of(), napr.:
class MediaQuery extends InheritedWidget {
final MediaQueryData data;
static MediaQueryData of(BuildContext context) {
return context.dependOnInheritedWidget<MediaQuery>()!.data;
}
}
dependOnInheritedWidget
hleda InheritedWidget daneho typu ve stromu smerem nahoru az k rootu, pokud ho najde, tak vrati v tomto pripadedata
, jinak vyhlasi error- krom navraceni InheritedWidgetu taky registruje volajici widget do zavislosti na danem InheritedWidgetu, s kazdou zmenou se pak vyhodnoti
updateShouldNotify
a pripadne provede build zavislych widgetu (presdidChangeDependencies
)