Riverpod — Kompilierte Abhängigkeitsverwaltung für Flutter

Autor: IT Sectr Veröffentlicht: 2026-02-19 Lesezeit: 7 Min.

Riverpod — ein kompilierter Zustands- und Abhängigkeitsmanager für Flutter, erstellt von Remi Rousselet im Jahr 2021 als Nachfolger von Provider. Riverpod löst grundlegende Probleme von Provider: fehlende Kompilierzeitprüfung, Abhängigkeit von BuildContext und Komplexität mit ProviderNotFoundException. Laut pub.dev hat das Paket über 5.000 Likes und verdrängt Provider aktiv in neuen Projekten.

Wichtigste Punkte

  • ProviderRef — ein Objekt zum Zugriff auf andere Provider innerhalb eines Providers
  • AsyncValue — ein Wrapper für asynchrone Daten mit den Zuständen loading/error/data
  • Notifier — eine Klasse für veränderlichen Zustand mit Änderungsmethoden
  • ProviderScope — das Root-Widget, das alle Provider verwaltet
  • Code Generation — @riverpod-Annotationen zur automatischen Provider-Generierung

Was ist Riverpod?

Riverpod ist eine Bibliothek zur Zustandsverwaltung und Abhängigkeitsinjektion für Flutter, die Provider-Beschreibungen in sicheren Dart-Code kompiliert. Im Gegensatz zu Provider sind Riverpod-Provider nicht an BuildContext gebunden: Sie werden global oder in ProviderScope erstellt und sind von überall aus zugänglich. Der Compiler überprüft Typen, Abhängigkeiten und die Integrität des Provider-Graphen zur Build-Zeit und eliminiert damit Laufzeitfehler wie ProviderNotFoundException.

Riverpod verwendet das override-Modell zum Testen: Jeder Provider kann über ProviderScope.overrideWith überschrieben werden, ohne Unterklassen erstellen oder Interfaces mocken zu müssen. Dadurch werden Tests isoliert: Jeder Test erhält seine eigene Kopie des Abhängigkeitsgraphen, die vollständig kontrolliert wird.

Laut der Flutter Community Survey 2025 belegt Riverpod den dritten Platz in der Beliebtheit nach Provider und BLoC. Riverpod ist jedoch das am schnellsten wachsende Paket: +120% Installationen im Jahr 2024. Hauptgründe: Kompilierzeitsicherheit, kein ProviderNotFoundException, integrierte asynchrone Unterstützung durch AsyncValue.

Provider-Typen

Riverpod bietet 8 Provider-Typen, jeder für ein bestimmtes Szenario: Provider (Konstante/Dienst), StateProvider (primitiver Zustand), StateNotifierProvider (komplexe Logik mit StateNotifier), ChangeNotifierProvider (für Migration von Provider), FutureProvider (asynchrone Daten, einmalig), StreamProvider (reaktiver Stream), NotifierProvider (neue API, Flutter 3.10+) und AsyncNotifierProvider (asynchroner Notifier).

Dart
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
  return CounterNotifier();
});

class CounterNotifier extends StateNotifier<int> {
  CounterNotifier() : super(0);

  void increment() => state++;
  void decrement() => state--;
}

class CounterScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Text('$count');
  }
}

ProviderRef — ein Objekt, das jedem Provider zum Zugriff auf andere Provider übergeben wird. ref.watch — Abonnement von Änderungen, ref.read — einmaliges Lesen, ref.invalidate — Cache-Zurücksetzung. ProviderRef ersetzt BuildContext von Provider: Jeder Provider kann andere Provider ohne Zugriff auf den Widget-Baum lesen. Dies ermöglicht den Aufbau eines Abhängigkeitsgraphen außerhalb der UI-Ebene.

ProviderScope — das Root-Widget, das für die Funktion von Riverpod erforderlich ist. ProviderScope speichert alle Provider, verwaltet ihren Lebenszyklus und cachet Werte. Ohne ProviderScope stürzt die App mit ProviderNotFoundException ab. ProviderScope kann verschachtelt werden — ein verschachtelter Scope überschreibt übergeordnete Provider, was zum Testen und zur Feature-Isolation verwendet wird.

AsyncValue und Arbeiten mit Asynchronität

AsyncValue — eine versiegelte Klasse von Riverpod zur Darstellung asynchroner Zustände. AsyncValue hat drei Varianten: AsyncData (erfolgreiche Daten), AsyncError (Fehler), AsyncLoading (Laden). Anstatt manuell zwischen loading/error/data zu wechseln, gibt jeder FutureProvider oder StreamProvider automatisch AsyncValue zurück, und das Widget behandelt alle drei Zustände über ref.watch.

Dart
final userProvider = FutureProvider((ref) async {
  final api = ref.watch(apiProvider);
  return await api.fetchUser();
});

class UserScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final userAsync = ref.watch(userProvider);
    return userAsync.when(
      data: (user) => UserWidget(user),
      error: (e, _) => ErrorWidget(e.toString()),
      loading: () => CircularProgressIndicator(),
    );
  }
}

AsyncValue.when — eine Methode zum Pattern-Matching aller drei Zustände. Der Compiler prüft, dass alle drei Fälle behandelt werden — wenn Sie loading oder error vergessen, wird der Code nicht kompiliert. AsyncValue.whenData — nur für data (wenn loading/error nicht benötigt werden). AsyncValue.guard — ein Wrapper über try-catch zur Konvertierung von Ausnahmen in AsyncError. keepAlive — ein Flag, das verhindert, dass der Provider-Cache beim Verlassen des Gültigkeitsbereichs zerstört wird.

Code-Generierung und @riverpod

Code-Generierung — eine Schlüsselfunktion von Riverpod 2.0+. Die @riverpod-Annotation auf einer Funktion generiert automatisch einen Provider mit dem richtigen Typ, Refactoring-Unterstützung und Autovervollständigung. Die Code-Generierung verwendet riverpod_generator und build_runner. Der Entwickler schreibt eine reine Funktion, und alles andere — Typen, Klassen, Factory-Konstruktoren — wird automatisch generiert.

Dart
@riverpod
String helloWorld(HelloWorldRef ref) {
  return 'Hello World';
}

// Generiert: final helloWorldProvider = Provider((ref) => 'Hello World');

@riverpod
class Counter extends _$Counter {
  int build() => 0;
  void increment() => state++;
}

Notifier — die neue API für veränderlichen Zustand mit Code-Generierung. Notifier ist eine Klasse mit einer build()-Methode und Zustandsänderungsmethoden. Im Gegensatz zu StateNotifier benötigt Notifier keine separate Zustandsklasse und bietet direkten Zugriff auf state über Getter/Setter. Riverpod generiert automatisch einen NotifierProvider für jede mit @riverpod annotierte Notifier-Klasse.

build_runner: Die Code-Generierung wird mit dem Befehl dart run build_runner build gestartet. Generierte Dateien haben das Suffix .g.dart und werden in den Quellcode importiert. Wenn sich Annotationen oder Provider-Typen ändern, muss die Code-Generierung neu gestartet werden. Riverpod 2.x empfiehlt Code-Generierung für alle neuen Projekte — die manuelle Provider-Erstellung wird veraltet.

Riverpod vs Provider

Hauptunterschiede zwischen Riverpod und Provider: Unabhängigkeit von BuildContext, Kompilierzeitsicherheit, integrierte asynchrone Unterstützung, automatisches Caching und Testen per override. Provider benötigt BuildContext für den Zugriff auf Zustände (context.watch, context.read), Riverpod verwendet WidgetRef und global deklarierte Provider.

EigenschaftProviderRiverpod
BuildContext-AbhängigkeitJaNein
KompilierzeitprüfungNeinJa (über @riverpod)
ProviderNotFoundExceptionLaufzeitUnmöglich
AsynchronitätManuellAsyncValue (integriert)
TestenWrapper in ProviderProviderScope.overrideWith
CachingNeinAutomatisch + keepAlive

Migration von Provider: Riverpod unterstützt ChangeNotifierProvider.adaptive zur Verwendung bestehender ChangeNotifier ohne Umschreiben. Schrittweise Migration: Zuerst werden neue Funktionen mit Riverpod geschrieben, dann werden alte Provider-Instanzen über einen Adapter durch Riverpod-Provider ersetzt. Beide Pakete können in einem Projekt koexistieren, was eine Migration ohne Entwicklungsstopp ermöglicht.

Riverpod testen

Riverpod testen basiert auf ProviderScope.overrideWith. Jeder Provider wird innerhalb eines Test-ProviderScope ohne Mocks oder DI-Container überschrieben. ProviderContainer — eine isolierte Umgebung für Tests ohne Flutter (reines Dart), die das Testen von Providern ohne Widget-Rendering ermöglicht.

Dart
import 'package:flutter_test/flutter_test.dart';
import 'package:riverpod/riverpod.dart';

void main() {
  test('Counter increments correctly', () {
    final container = ProviderContainer();
    container.read(counterProvider.notifier).increment();
    expect(container.read(counterProvider), 1);
  });

  testWidgets('UI updates on increment', (tester) async {
    await tester.pumpWidget(
      ProviderScope(
        overrides: [counterProvider.overrideWithValue(5)],
        child: CounterScreen(),
      ),
    );
    expect(find.text('5'), findsOneWidget);
  });
}

ProviderContainer — ohne Flutter. Verwenden Sie ProviderContainer für Unit-Tests von Providern ohne Widgets. overrideWithValue — Ersetzen eines Providers durch einen bestimmten Wert. overrideWith — Ersetzen durch eine Provider-Factory (zum Mocken von Diensten). autodispose — in Tests überprüfen Sie, ob der Provider beim Verlassen des Gültigkeitsbereichs mit container.dispose() zerstört wird.

Häufig gestellte Fragen

Wie unterscheidet sich Riverpod von BLoC?

Riverpod ist eine Zustandsverwaltungsbibliothek mit globalen Providern, AsyncValue und Code-Generierung. BLoC ist ein Architekturmuster mit Event → Stream → State. Riverpod ist einfacher zu erlernen und bietet eine bessere DX durch @riverpod-Annotationen. BLoC bietet strenge Geschäftslogik-Isolierung und Ereignisverfolgung durch BlocObserver. Die Wahl hängt vom Projektparadigma ab: Riverpod ist näher an Provider, BLoC — an reaktiven Streams.

Was ist autodispose in Riverpod?

Autodispose ist ein Mechanismus zur automatischen Zerstörung eines Providers, wenn niemand ihn abonniert hat. Standardmäßig führen alle Riverpod-Provider autodispose durch: Wenn ein Widget den Baum verlässt, wird der Provider aus dem Speicher entfernt. keepAlive — ein Flag, das autodispose für Provider deaktiviert, die immer leben sollen (API-Clients, Repositories, Einstellungen). Dies verhindert Speicherlecks — ungenutzte Provider werden automatisch zerstört.

Wie funktioniert ref.invalidate?

ref.invalidate — eine Methode, die den Provider-Cache zwangsweise zurücksetzt. Nach invalidate wird der Provider beim nächsten Lesen neu erstellt: FutureProvider führt die asynchrone Funktion erneut aus, StreamProvider abonniert den Stream neu. Verwenden Sie invalidate zum erzwungenen Daten-Refresh (Pull-to-Refresh, Benutzerwechsel). ref.refresh — eine Kombination aus invalidate + Lesen: setzt zurück und liest sofort den neuen Wert in einem Vorgang.

Kann Riverpod ohne Code-Generierung verwendet werden?

Ja. Riverpod 1.x funktioniert nur ohne Code-Generierung — Provider werden manuell mit Provider(), StateNotifierProvider(), FutureProvider() usw. erstellt. Riverpod 2.x unterstützt beide Ansätze. Ohne Code-Generierung gibt es mehr Boilerplate, aber keine Abhängigkeit von build_runner und dart run build_runner build. Für kleine Projekte (bis zu 30 Providern) ist die manuelle Erstellung gerechtfertigt, für große ist die Code-Generierung obligatorisch.

Was sind Family-Provider?

Family — ein Provider-Modifikator, der einen externen Parameter akzeptiert. Zum Beispiel userProvider(123) — ein Provider, der einen Benutzer mit ID 123 lädt. Family-Provider cachen das Ergebnis für jeden eindeutigen Parameter separat. Verwenden Sie Family für Listen von Elementen, bei denen jedes Element per ID geladen wird. Der Family-Modifikator ist für alle Provider-Typen verfügbar: Provider.family, FutureProvider.family, StreamProvider.family.

Zusammenfassung

  • Riverpod — ein kompilierter Zustandsmanager, Nachfolger von Provider ohne ProviderNotFoundException
  • ProviderRef — ein Ersatz für BuildContext zum Zugriff auf Provider innerhalb anderer Provider
  • AsyncValue — eine versiegelte Klasse mit loading/error/data-Zuständen für asynchrone Daten
  • @riverpod Code-Generierung — automatische Typinferenz und Provider-Factories
  • ProviderScope.overrideWith — isoliertes Testen ohne Mocks und DI-Container
  • Family — parametrisierte Provider mit individuellem Caching
  • autodispose und keepAlive — automatisches Provider-Lebenszyklus-Management

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch