Grunderna i Provider-paketet
Lär er använda Provider-paketet, en populär Flutter-lösning för enkel och skalbar state-hantering i hela applikationen.
Grunderna i Provider-paketet är en gratis lektion i Mobilutveckling med Flutter på CoddyKit. Detta är lektion 2 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Mobilutveckling med Flutter, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Mobilutveckling med Flutter innehåller totalt 4 lektioner.
Vad är Provider?
Paketet Provider är en populär och enkel lösning för tillståndshantering i Flutter. Det bygger på Flutters egen InheritedWidget, vilket gör det effektivt och lätt att förstå.
Det hjälper dig att dela data och tillstånd i hela widgetträdet utan komplexa callbacks eller prop drilling.
Tillståndshållaren: ChangeNotifier
I centrum för Provider finns klassen ChangeNotifier. Du utökar den här klassen för alla objekt som innehåller tillstånd som du vill dela.
När ditt tillstånd ändras anropar du notifyListeners() för att tala om för alla lyssnande widgets att de ska byggas om.
import 'package:flutter/material.dart';
// 1. Extend ChangeNotifier
class MyCounter extends ChangeNotifier {
int _count = 0; // Private state variable
// Getter to access the count
int get count => _count;
// Method to modify state and notify listeners
void increment() {
_count++;
notifyListeners(); // Important! Triggers UI updates
}
}Göra tillstånd tillgängligt
För att göra din ChangeNotifier-instans tillgänglig för widgets använder du en ChangeNotifierProvider. Du omsluter en del av ditt widgetträd, vanligtvis hela appen, med den.
Callbacken create tillhandahåller en instans av ditt tillståndsobjekt.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
// Our state class from before
class MyCounter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
void main() {
runApp(
// Wrap the app with ChangeNotifierProvider
ChangeNotifierProvider(
create: (context) => MyCounter(), // Create an instance
child: MyApp(), // The widget tree that can access MyCounter
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Provider Setup')),
body: Center(
child: Text(
'MyCounter is now provided!',
style: TextStyle(fontSize: 24),
),
),
),
);
}
}Lyssna efter ombyggnad av gränssnittet
Det vanligaste sättet för en widget att lyssna efter tillståndsändringar och bygga om sitt gränssnitt är att använda context.watch. Den här metoden gör widgeten beroende av det tillhandahållna tillståndet.
När notifyListeners() anropas byggs alla widgets som använder watch om.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class MyCounter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => MyCounter(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 1. Use context.watch<MyCounter>() to get the current state
// This widget will rebuild when MyCounter changes.
final counter = context.watch<MyCounter>();
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Watch for Changes')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Count: ${counter.count}', // Display the count
style: TextStyle(fontSize: 32),
),
SizedBox(height: 20),
// Button to increment (action will be added next)
ElevatedButton(
onPressed: () {
// How to trigger increment? See next scene!
},
child: Text('Increment (Not yet connected)'),
),
],
),
),
),
);
}
}Åtgärder utan ombyggnad
Ibland behöver du komma åt tillståndsmetoder, som increment(), men vill inte att widgeten ska byggas om. Använd då context.read.
Det ger åtkomst till tillståndsobjektet vid ett enda tillfälle och upprättar ingen lyssnarrelation.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class MyCounter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => MyCounter(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = context.watch<MyCounter>(); // Listen for UI updates
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Read for Actions')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Count: ${counter.count}',
style: TextStyle(fontSize: 32),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 1. Use context.read<MyCounter>() to get the instance
// 2. Call the increment method
context.read<MyCounter>().increment();
},
child: Text('Increment Counter'),
),
],
),
),
),
);
}
}Alternativ för åtkomst vid ett enda tillfälle
Innan context.read var det vanligaste sättet att komma åt tillstånd utan att lyssna Provider.of.
Det fungerar precis som context.read, men read föredras ofta eftersom det är kortare. Båda lämpar sig för händelsehanterare som onPressed.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class MyCounter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => MyCounter(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = context.watch<MyCounter>(); // UI listens
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Provider.of(listen: false)')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Count: ${counter.count}',
style: TextStyle(fontSize: 32),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// Use Provider.of with listen: false for one-time access
Provider.of<MyCounter>(context, listen: false).increment();
},
child: Text('Increment Counter (using Provider.of)'),
),
],
),
),
),
);
}
}Detaljerad ombyggnad med Consumer
Widgeten Consumer är ett annat sätt att lyssna efter tillståndsändringar. Till skillnad från context.watch(), som bygger om hela widgeten, bygger Consumer endast om sitt direkta barn, funktionen builder.
Det kan vara användbart för prestandan om endast en liten del av en stor widget behöver reagera på tillståndsändringar.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class MyCounter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => MyCounter(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Consumer Widget')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'This text does NOT rebuild.',
style: TextStyle(fontSize: 20, color: Colors.grey),
),
SizedBox(height: 20),
// Only the Text widget inside Consumer rebuilds
Consumer<MyCounter>(
builder: (context, counter, child) {
print('Consumer rebuilt!'); // See this in console
return Text(
'Count: ${counter.count}',
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read<MyCounter>().increment();
},
child: Icon(Icons.add),
),
),
);
}
}Tillhandahålla flera tillstånd
För appar med flera oberoende tillståndsobjekt kan det bli rörigt att omsluta appen med många ChangeNotifierProvider. MultiProvider förenklar detta.
Den tar emot en lista med providers, vilket gör widgetträdet renare och lättare att hantera.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class MyCounter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
class MyThemeSettings extends ChangeNotifier {
bool _isDark = false;
bool get isDark => _isDark;
void toggleTheme() {
_isDark = !_isDark;
notifyListeners();
}
}
void main() {
runApp(
MultiProvider( // Use MultiProvider for multiple states
providers: [
ChangeNotifierProvider(create: (context) => MyCounter()),
ChangeNotifierProvider(create: (context) => MyThemeSettings()),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Access both states using watch
final counter = context.watch<MyCounter>();
final theme = context.watch<MyThemeSettings>();
return MaterialApp(
theme: theme.isDark ? ThemeData.dark() : ThemeData.light(),
home: Scaffold(
appBar: AppBar(title: Text('MultiProvider Demo')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: ${counter.count}', style: TextStyle(fontSize: 28)),
SizedBox(height: 20),
Text('Dark Mode: ${theme.isDark ? "On" : "Off"}', style: TextStyle(fontSize: 28)),
SizedBox(height: 30),
ElevatedButton(
onPressed: () => context.read<MyThemeSettings>().toggleTheme(),
child: Text('Toggle Theme'),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<MyCounter>().increment(),
child: Icon(Icons.add),
),
),
);
}
}Snabbtest om Provider
Vilket av följande är huvudsyftet med context.read i paketet Provider?
Sammanfattning av grunderna i Provider
Du har lärt dig grunderna i paketet Provider!
ChangeNotifierinnehåller appens tillstånd.ChangeNotifierProvidergör tillståndet tillgängligt.context.watchlyssnar efter tillståndsändringar och bygger om gränssnittet.() context.readger åtkomst till tillståndet för åtgärder utan ombyggnad.() Provider.of(listen: false)är ett äldre alternativ tillread.Consumermöjliggör detaljerad ombyggnad av gränssnittet.MultiProviderhjälper dig att hantera flera tillståndsobjekt på ett strukturerat sätt.
Provider är ett kraftfullt och flexibelt verktyg för att hantera tillstånd i dina Flutter-appar!
Lär dig Dart med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 22
- Lektioner
- 88
Vanliga frågor
Är lektionen ”Grunderna i Provider-paketet” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Mobilutveckling med Flutter, inklusive ”Grunderna i Provider-paketet”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Mobilutveckling med Flutter innehåller totalt 4 lektioner.
Vad lär jag mig i ”Grunderna i Provider-paketet”?
Lär er använda Provider-paketet, en populär Flutter-lösning för enkel och skalbar state-hantering i hela applikationen. Ni övar på Mobilutveckling med Flutter med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Mobilutveckling med Flutter?
Du behöver inga förkunskaper. Utbildningen i Mobilutveckling med Flutter på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Grunderna i Provider-paketet”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Mobilutveckling med Flutter-lektionen?
Ja. Varje Mobilutveckling med Flutter-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- setState och InheritedWidget
- Grunderna i Provider-paketet
- Riverpod för state-hantering
- BLoC-mönstret med Streams