Provider — pachet de gestionare a stării pentru Flutter, creat de Rémi Rousselet în 2019 ca un strat peste InheritedWidget. Provider rezolvă problema transmiterii datelor în josul arborelui de widgeturi fără props drilling: orice widget obține acces la stare prin context.read<T>() sau context.watch<T>(). Conform pub.dev, Provider este cel mai popular manager de stare Flutter cu peste 25 de mii de aprecieri.
Principalul
Provider — pachet pentru gestionarea stării și injectarea dependențelor în Flutter, construit pe baza InheritedWidget. Provider pune la dispoziție un obiect (stare, serviciu, depozit) în arborele de widgeturi și reconstruiește automat UI la modificarea datelor. Spre deosebire de utilizarea directă a InheritedWidget, Provider elimină tot boilerplate-ul: nu este nevoie să scrieți o subclasă InheritedWidget, să configurați metoda statică of() și să gestionați îmbricarea.
Provider este recomandat oficial de Google pentru gestionarea stării în Flutter (Flutter Team, 2019-2023). Pachetul face parte din Flutter Ecosystem și este susținut de echipa Flutter. La momentul lansării, Provider a fost propus ca înlocuitor pentru variabilele globale și InheritedWidget: orice obiect este accesibil din orice loc fără a fi transmis prin constructor.
Conform Flutter Community Survey 2025, Provider este utilizat în 72% dintre aplicațiile Flutter. Principalele motive de popularitate: prag minim de intrare, suport încorporat pentru ChangeNotifier, compatibilitate cu alte arhitecturi (MVVM, BLoC) și absența dependențelor externe.
ChangeNotifier — clasă încorporată Flutter care implementează modelul Listener. ChangeNotifier notifică abonații despre modificare prin apelul notifyListeners(). În contextul Provider, ChangeNotifier este clasa principală pentru stare: se creează o clasă care moștenește ChangeNotifier cu câmpuri și metode care apelează notifyListeners() după modificarea datelor.
class CounterProvider extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void reset() {
_count = 0;
notifyListeners();
}
}Reguli notifyListeners: apelați după modificarea completă a datelor — nu la mijlocul metodei, ci la sfârșit. Dacă metoda execută mai multe modificări, apelați notifyListeners() o dată după toate modificările, nu după fiecare. Pentru actualizări în masă, utilizați notifyListeners în combinație cu modele similare setState.
Alternative la ChangeNotifier: ValueNotifier — pentru o singură valoare (potrivit pentru primitive), StateNotifier — din pachetul state_notifier (rar folosit singur). Majoritatea soluțiilor Provider folosesc ChangeNotifier datorită suportului încorporat și simplității.
Consumer — widget care se abonează la ChangeNotifier și se reconstruiește la fiecare apel notifyListeners(). Consumer acceptă o funcție builder cu trei parametri: context, model, child. Child — widget independent de model, pe care Consumer nu îl reconstruiește. Aceasta este o optimizare: dacă în interiorul Consumer există un widget static (icoană, text fără date), acesta este transmis prin child și nu este recreat.
Consumer<CounterProvider>(
builder: (context, provider, child) => Column(
children: [
child!, // nu se reconstruiește
Text('${provider.count}'),
ElevatedButton(
onPressed: () => provider.increment(),
child: Icon(Icons.add),
),
],
),
child: Text('Contor:'),
)context.watch — metodă de extensie BuildContext pentru abonarea la Provider. Returnează modelul și abonează widgetul curent la modificările sale. context.read — acces fără abonare (pentru handler-e onPressed, initState și dispose). context.select — abonare la un anumit câmp al modelului fără reconstruire la modificarea altor câmpuri. Select este cea mai performantă opțiune pentru modele complexe cu 10+ câmpuri.
Când să utilizați Consumer, watch sau select: Consumer — când este necesar un widget child pentru optimizare. watch — în metoda build pentru citire simplă. select — când modelul are mai multe câmpuri, dar widgetul depinde doar de unul. Provider se dezabonează automat la distrugerea widgetului, prevenind scurgerile de memorie.
MultiProvider — widget pentru înregistrarea mai multor Provider fără îmbricare. În locul unui arbore cu 5 niveluri Provider → Provider → Provider, MultiProvider acceptă o listă de provideri. Fiecare Provider ulterior poate utiliza anteriorii prin constructor. MultiProvider este modul standard de organizare a nivelului rădăcină al aplicației.
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CartProvider()),
ChangeNotifierProvider(create: (_) => AuthProvider()),
ProxyProvider<AuthProvider, OrderProvider>(
update: (_, auth, __) => OrderProvider(auth.userId),
),
],
child: MaterialApp(home: HomePage()),
)ProxyProvider — Provider care depinde de un alt Provider. ProxyProvider preia valori din alți provideri și le transmite propriului obiect. De exemplu, OrderProvider depinde de AuthProvider. ChangeNotifierProxyProvider — versiunea ProxyProvider pentru ChangeNotifier.
StreamProvider și FutureProvider: StreamProvider se abonează la un flux (Firebase, WebSocket) și actualizează Consumer la fiecare eveniment nou. FutureProvider — pentru inițializare asincronă: pornește Future, arată încărcarea, apoi transmite rezultatul widgeturilor.
Provider se testează prin învelirea widgetului în MultiProvider cu valori de test. Pentru test nu este necesar un API real sau o bază de date — Provider este înlocuit cu un obiect simulat. Pachetul provider oferă ProviderScope pentru izolarea testelor — fiecare test își creează propriul arbore Provider independent de altele.
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Counter increments on button tap',
(tester) async {
await tester.pumpWidget(
ChangeNotifierProvider(
create: (_) => CounterProvider(),
child: CounterScreen(),
),
);
await tester.tap(find.byKey(Key('increment')));
await tester.pump();
expect(find.text('1'), findsOneWidget);
},
);
}MockProvider: pentru testarea widgeturilor cu Provider dependent de API, creați o subclasă falsă sau utilizați mockito / mocktail. Provider nu necesită unelte speciale de simulare — orice obiect care moștenește ChangeNotifier poate fi transmis prin create fără a apela serviciul real.
Performanța Provider se bazează pe InheritedWidget: la modificarea Provider, toate widgeturile abonate prin context.watch sau Consumer sunt reconstruite. Pentru a preveni redesenele inutile, utilizați context.select (abonare la un anumit câmp), Consumer cu parametrul child și const pentru widgeturi statice.
| Metodă | Abonare | Redesenează | Utilizare |
|---|---|---|---|
| context.watch | Model complet | Orice modificare | Widgeturi simple |
| Consumer | Model complet | Orice modificare | Cu optimizare child |
| context.select | Câmp specific | Doar la modificarea câmpului | Modele complexe |
| context.read | Nu | Niciodată | Handlere de evenimente |
Limitări: Provider nu suportă izolarea logicii de business la nivel de Event (ca BLoC). Toate modificările au loc prin apelul direct al metodelor ChangeNotifier, ceea ce poate duce la lanțuri necontrolate de modificări. Pentru scenarii complexe, Provider este inferior BLoC și Riverpod.
Întrebări frecvente
Provider — strat peste InheritedWidget pentru injectarea dependențelor cu ChangeNotifier. BLoC — model arhitectural cu Event + Stream pentru izolarea logicii. Provider este mai ușor de învățat, BLoC structurează codul mai strict. Provider este potrivit pentru aplicații mici și stare UI, BLoC — pentru logică de business complexă.
ChangeNotifierProvider — tip de Provider pentru instanțe ChangeNotifier. Creează obiectul prin create, îl pune la dispoziție descendenților și reconstruiește Consumer la apelul notifyListeners. ChangeNotifierProvider apelează automat dispose pe ChangeNotifier la eliminarea din arbore.
Folosiți context.select în loc de context.watch — widgetul se redesenează doar la modificarea câmpului selectat. Împărțiți ChangeNotifier-urile mari în mai multe mici (un model — o responsabilitate). Utilizați Consumer child pentru părțile statice.
Da. Provider (fără ChangeNotifier) — pentru injectarea obiectelor imutabile. ValueListenableProvider — pentru ValueNotifier. StreamProvider — pentru fluxuri. FutureProvider — pentru Future. ProxyProvider — pentru Provideri dependenți de alții. ChangeNotifier este necesar doar pentru stare mutabilă cu actualizare UI.
ProviderNotFoundException — excepție de runtime care apare la încercarea de a obține un Provider care nu a fost declarat mai sus în arborele de widgeturi. Soluție: mutați Provider-ul mai sus în arbore sau folosiți MultiProvider la nivelul MaterialApp pentru dependențe globale.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și