Skip to content

Level 2 · Intermediate Real Apps

Goal: build multi-screen apps that load data, remember it, share state cleanly between widgets, and come with tests you trust.

Three ideas carry this level:

  1. Navigation is state. Imperative push/pop is fine for detours; anything addressable (deep links, the web) should be derived from a location with a router.
  2. Share state by subscription, not by passing it everywhere. InheritedWidget is the mechanism; Provider and Riverpod are the ergonomic layers on top, and the skill is subscribing to exactly what each widget needs.
  3. Put I/O behind seams. HTTP clients and storage are injected, so every screen can be tested with fakes — no network, no disk, no device.

Modules

  1. Navigation: push, pop & Returning Results — the route stack, awaiting results, PopScope for unsaved changes
  2. Declarative Routing with go_router — nested routes, parameters, auth redirects, shell routes
  3. Lifting State & InheritedWidget — who rebuilds and why, measured
  4. Provider & ChangeNotifier — watch, read and select, with rebuild counts
  5. Riverpod — Notifier, AsyncNotifier, derived providers, overrides in tests
  6. Async UI: FutureBuilder & StreamBuilder — snapshot states, retry, and the future-in-build trap
  7. HTTP & JSON — a typed client with validation, error mapping and MockClient tests
  8. Local Persistence — shared_preferences, atomic JSON files, schema migration, when to use SQLite
  9. Testing: Unit, Widget & Golden Tests — table-driven tests, fakes with Completer, golden images and their failures
  10. Project — A Reading List App — go_router + Riverpod + a storage repository, with a full test suite

What you need before starting

  • Level 1, or equivalent experience: stateful widgets, layout, forms and lists.
  • Comfort with Dart Futures and Streams (Dart Mastery Path).
  • For lesson 07, the basics of HTTP and JSON APIs; the REST API Mastery Path covers them.

How the examples were checked

Every example was run with Flutter 3.44.8 and Dart 3.12.2 using go_router 18.0.2, provider 6.1.5+1, flutter_riverpod 3.4.3, http 1.6.0 and shared_preferences 2.5.6. Outputs are the actual print output of flutter test, with the tool's per-test progress lines removed for readability. Several lessons include first attempts that failed (a setState that returned a Future, a test expectation that was wrong) because the failures teach as much as the fixes.

What wasn't run

No real network calls were made — HTTP examples use MockClient against a reserved example domain — and platform storage was replaced by in-memory fakes in tests. Nothing was run on a phone or simulator; lesson 08 and the project say exactly what that does and doesn't prove.