Navigation und API

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

Listen mit ListView

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