Mobilutvikling med Flutter · leksjon

Grunnleggende om Provider-pakken

Lær å bruke Provider-pakken, en populær Flutter-løsning for enkel og skalerbar tilstandsbehandling i hele applikasjonen.

Leksjon 2 av 410 trinn

Grunnleggende om Provider-pakken er en gratis leksjon i Mobilutvikling med Flutter på CoddyKit. Dette er leksjon 2 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Mobilutvikling med Flutter, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Mobilutvikling med Flutter inneholder totalt 4 leksjoner.

Hva er Provider?

Provider-pakken er en populær og enkel løsning for tilstandshåndtering i Flutter. Den er bygget oppå Flutters egen InheritedWidget, noe som gjør den effektiv og lett å forstå.

Den hjelper Dem med å dele data og tilstand på tvers av widget-treet uten komplekse callback-funksjoner eller prop-drilling.

Databeholderen: ChangeNotifier

Hjertet i Provider er klassen ChangeNotifier. De utvider denne klassen for objekter som inneholder tilstand De vil dele.

Når tilstanden endres, kaller De notifyListeners() for å varsle alle widgets som lytter, slik at de bygges på nytt.

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
  }
}

Gjøre tilstanden tilgjengelig

For å gjøre ChangeNotifier-instansen tilgjengelig for widgets bruker De en ChangeNotifierProvider. De pakker inn en del av widget-treet (vanligvis hele appen) med den.

Callback-funksjonen create oppretter en instans av tilstandsobjektet.

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),
          ),
        ),
      ),
    );
  }
}

Lytte etter nybygging av brukergrensesnittet

Den vanligste måten en widget kan lytte etter tilstandsendringer og bygge brukergrensesnittet på nytt, er å bruke context.watch(). Denne metoden gjør widgeten avhengig av den oppgitte tilstanden.

Når notifyListeners() kalles, bygges alle widgets som bruker watch, på nytt.

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)'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Handlinger uten nybygging

Noen ganger trenger De tilgang til tilstandsmetoder (som increment()), men vil ikke at widgeten skal bygges på nytt. Da bruker De context.read().

Den gir engangstilgang til tilstandsobjektet og oppretter ikke et lytteforhold.

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 for engangstilgang

Før context.read() var den vanligste måten å få tilgang til tilstanden uten å lytte, Provider.of(context, listen: false).

Den fungerer nøyaktig som context.read(), men read foretrekkes ofte fordi den er kortere. Begge egner seg for hendelsesbehandlere 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)'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Detaljert nybygging med Consumer

Widgeten Consumer er en annen måte å lytte etter tilstandsendringer på. I motsetning til context.watch(), som bygger hele widgeten på nytt, bygger Consumer bare det direkte underordnede elementet (funksjonen builder) på nytt.

Dette kan være nyttig for ytelsen hvis bare en liten del av en stor widget må reagere på tilstandsendringer.

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),
        ),
      ),
    );
  }
}

Tilby flere tilstander

I apper med flere uavhengige tilstandsobjekter kan det bli uoversiktlig å pakke appen inn i mange ChangeNotifierProvider-er. MultiProvider forenkler dette.

Den tar imot en liste med providers, slik at widget-treet blir ryddigere og enklere å administrere.

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),
        ),
      ),
    );
  }
}

Hurtigsjekk av Provider

Hva er hovedformålet med context.read() i Provider-pakken?

Oppsummering av Provider-grunnprinsipper

De har lært det viktigste om Provider-pakken!

  • ChangeNotifier inneholder applikasjonens tilstand.
  • ChangeNotifierProvider gjør denne tilstanden tilgjengelig.
  • context.watch() lytter etter tilstandsendringer og bygger brukergrensesnittet på nytt.
  • context.read() gir tilgang til tilstanden for handlinger uten å bygge på nytt.
  • Provider.of(listen: false) er et eldre alternativ til read.
  • Consumer muliggjør detaljert nybygging av brukergrensesnittet.
  • MultiProvider gjør det enklere å administrere flere tilstandsobjekter på en ryddig måte.

Provider er et kraftig og fleksibelt verktøy for håndtering av tilstand i Flutter-appene Deres!

Gratis å komme i gang

Lær deg Dart med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
22
Leksjoner
88

Ofte stilte spørsmål

Er leksjonen «Grunnleggende om Provider-pakken» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Mobilutvikling med Flutter, inkludert «Grunnleggende om Provider-pakken», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Mobilutvikling med Flutter inneholder totalt 4 leksjoner.

Hva lærer jeg i «Grunnleggende om Provider-pakken»?

Lær å bruke Provider-pakken, en populær Flutter-løsning for enkel og skalerbar tilstandsbehandling i hele applikasjonen. Du øver på Mobilutvikling med Flutter med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Mobilutvikling med Flutter?

Ingen tidligere erfaring er nødvendig. Mobilutvikling med Flutter på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 2 av 4.

Hvor lang tid tar leksjonen «Grunnleggende om Provider-pakken»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Mobilutvikling med Flutter-leksjonen?

Ja. Alle Mobilutvikling med Flutter-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. setState og InheritedWidget
  2. Grunnleggende om Provider-pakken
  3. Riverpod for tilstandsbehandling
  4. BLoC-mønsteret med Streams
← Tilbake til Mobilutvikling med Flutter