Navigation und API

35 MinutenEine Liste anzeigen, Screens verbinden und echte Daten mit einem Coding Agent anbinden

Listen mit ListView

ListView.builder erzeugt Einträge erst, wenn sie sichtbar werden. Damit bleiben auch lange Listen performant.

ListView.separated(
  itemCount: cities.length,
  itemBuilder: (context, index) {
    final city = cities[index];
    return ListTile(
      title: Text(city.name),
      onTap: () { /* Navigation, siehe unten */ },
    );
  },
  separatorBuilder: (context, index) => const Divider(height: 1),
)

Navigation mit Navigator

Der Navigator verwaltet einen Stapel von Screens (Routes).

  • Navigieren: Route auf den Stapel legen, Navigator.push(…)
  • Zurück: oberste Route entfernen, Navigator.pop(context)
  • Angezeigt wird immer die oberste Route
onTap: () => Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => WeatherScreen(city: city)),
),

Laden beim Öffnen

Jeder Wetter-Screen erzeugt sein eigenes ViewModel und lädt das Wetter in initState.

class _WeatherScreenState extends State<WeatherScreen> {
  final _viewModel = WeatherViewModel();

  @override
  void initState() {
    super.initState();
    _viewModel.loadWeather(widget.city);
  }
  // dispose() und build() wie bisher
}

API-Anbindung mit einem Coding Agent

Aufgabe für den Agent: ein ApiWeatherRepository für Open-Meteo bauen und im ViewModel einsetzen.

  • Plan anfordern und prüfen, bevor Code entsteht
  • umsetzen lassen, flutter analyze, App testen
  • Diff lesen und erklären können
  • erst dann committen

Das Paket http

Pakete kommen von pub.dev und werden mit flutter pub add eingebunden.

final uri = Uri.https('api.open-meteo.com', '/v1/forecast', {
  'latitude': '${city.latitude}',
  'longitude': '${city.longitude}',
  'current': 'temperature_2m,weather_code,wind_speed_10m',
});
final response = await _client.get(uri);
if (response.statusCode != 200) {
  throw Exception('HTTP-Fehler ${response.statusCode}');
}
final json = jsonDecode(utf8.decode(response.bodyBytes));
return ForecastResponse.fromJson(json).current.toCurrentWeather();

DTO und Datenmodell

Die JSON-Antwort bekommt eigene Klassen (DTOs). Sie werden auf unser Datenmodell abgebildet.

class CurrentDto {
  // const-Konstruktor und final-Felder ...

  factory CurrentDto.fromJson(Map<String, dynamic> json) => CurrentDto(
    temperature: (json['temperature_2m'] as num).toDouble(),
    weatherCode: json['weather_code'] as int,
    windSpeed: (json['wind_speed_10m'] as num).toDouble(),
  );
}

Der Nutzen der Architektur

Für echte Daten wurde kein einziges Widget geändert.

$ git diff --stat schritt-08 schritt-09
 android/app/src/main/AndroidManifest.xml |  2 ++
 lib/data/api/open_meteo_dto.dart         | 31 ++++++++++
 lib/data/api_weather_repository.dart     | 52 ++++++++++++++++
 lib/ui/weather_view_model.dart           |  4 +-
 pubspec.lock                             | 32 ++++++++++
 pubspec.yaml                             |  1 +

Übungen

Selbst oder mit einem Coding Agent umsetzen, jeweils Plan und Diff prüfen.

  • Stadtsuche über die Geocoding-API von Open-Meteo
  • 7-Tage-Vorhersage im Wetter-Screen
  • Button „Erneut versuchen“ bei Fehlern
  • Pull-to-Refresh im Wetter-Screen
  • Unit-Tests für das ViewModel mit FakeWeatherRepository
  • Favoriten: Städte auf dem Gerät speichern