Simulate fetching weather data from multiple cities concurrently, then aggregate and analyze the results. This demonstrates concurrent API calls, data processing, and timeout handling.
Requirements
Create a WeatherData class with city, temperature, condition, and humidity
Simulate API calls with random delays (500ms-2s per city)
Fetch weather for 6+ cities concurrently
Implement timeout handling (3 second limit per city)
Find the hottest and coldest cities
Calculate average temperature
Display a formatted weather report
Expected Output
Terminal
āāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Weather Data Service ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāā
Fetching weather data for 6 cities...
ā New York: 22°C, Partly Cloudy (Humidity: 65%)
ā London: 15°C, Rainy (Humidity: 78%)
ā Tokyo: 28°C, Sunny (Humidity: 45%)
ā Sydney: 31°C, Clear Sky (Humidity: 35%)
ā Dubai: 38°C, Hot (Humidity: 20%)
ā Moscow: 8°C, Cloudy (Humidity: 72%)
āāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā WEATHER REPORT ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāā
š„ Hottest City: Dubai (38°C)
āļø Coldest City: Moscow (8°C)
š Average Temperature: 23.7°C
ā±ļø Fetch Time: 1.8 seconds
š” Recommendations:
⢠Stay hydrated in Dubai! It's very hot.
⢠Bring a warm jacket to Moscow.
import 'dart:async';
import 'dart:math';
// Step 1: Weather data model
class WeatherData {
final String city;
final double temperature;
final String condition;
final int humidity;
final DateTime fetchTime;
WeatherData({
required this.city,
required this.temperature,
required this.condition,
required this.humidity,
}) : fetchTime = DateTime.now();
@override
String toString() {
String tempEmoji = temperature > 30 ? 'š„' :
temperature > 20 ? 'āļø' :
temperature > 10 ? 'š¤ļø' : 'āļø';
return '$tempEmoji $city: ${temperature.toStringAsFixed(0)}°C, $condition (Humidity: $humidity%)';
}
}
// Step 2: Simulated weather API call
Future fetchWeather(String city) async {
final random = Random();
// Simulate network delay (500ms - 2 seconds)
int delayMs = 500 + random.nextInt(1500);
await Future.delayed(Duration(milliseconds: delayMs));
// Step 3: Generate realistic weather based on city
final conditions = ['Sunny', 'Cloudy', 'Rainy', 'Clear Sky', 'Partly Cloudy', 'Hot', 'Windy', 'Mild'];
double baseTemp;
switch (city) {
case 'Dubai': baseTemp = 36; break;
case 'Moscow': baseTemp = 5; break;
case 'Tokyo': baseTemp = 25; break;
case 'Sydney': baseTemp = 28; break;
case 'London': baseTemp = 14; break;
case 'New York': baseTemp = 20; break;
case 'Mumbai': baseTemp = 32; break;
case 'Toronto': baseTemp = 10; break;
default: baseTemp = 18;
}
// Add random variation (-3 to +5 degrees)
double temperature = baseTemp + random.nextDouble() * 8 - 3;
int humidity = 20 + random.nextInt(60);
String condition = conditions[random.nextInt(conditions.length)];
print('ā $city: ${temperature.toStringAsFixed(0)}°C, $condition (Humidity: $humidity%)');
return WeatherData(
city: city,
temperature: temperature,
condition: condition,
humidity: humidity,
);
}
// Step 4: Fetch with timeout
Future fetchWeatherWithTimeout(String city) async {
try {
return await fetchWeather(city).timeout(
Duration(seconds: 3),
onTimeout: () {
print('ā ļø Timeout fetching weather for $city');
return null;
},
);
} catch (e) {
print('ā Error fetching $city: $e');
return null;
}
}
Future main() async {
print('āāāāāāāāāāāāāāāāāāāāāāāāāāāā');
print('ā Weather Data Service ā');
print('āāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
// Step 5: Cities to fetch
final cities = [
'New York', 'London', 'Tokyo',
'Sydney', 'Dubai', 'Moscow',
];
print('Fetching weather data for ${cities.length} cities...\n');
final totalStopwatch = Stopwatch()..start();
// Step 6: Fetch all concurrently
final futures = cities.map((city) => fetchWeatherWithTimeout(city));
final results = await Future.wait(futures);
totalStopwatch.stop();
// Step 7: Filter valid results
final validResults = results.whereType().toList();
if (validResults.isEmpty) {
print('ā No weather data available.');
return;
}
// Step 8: Calculate statistics
validResults.sort((a, b) => b.temperature.compareTo(a.temperature));
WeatherData hottest = validResults.first;
WeatherData coldest = validResults.last;
double totalTemp = validResults.fold(0, (sum, w) => sum + w.temperature);
double avgTemp = totalTemp / validResults.length;
// Step 9: Display report
print('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
print('ā WEATHER REPORT ā');
print('āāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
// Temperature ranking
print('š Temperature Ranking:');
for (int i = 0; i < validResults.length; i++) {
print(' ${i + 1}. ${validResults[i]}');
}
print('\nš Statistics:');
print('š„ Hottest City: ${hottest.city} (${hottest.temperature.toStringAsFixed(0)}°C)');
print('āļø Coldest City: ${coldest.city} (${coldest.temperature.toStringAsFixed(0)}°C)');
print('š Average Temperature: ${avgTemp.toStringAsFixed(1)}°C');
print('ā±ļø Fetch Time: ${(totalStopwatch.elapsedMilliseconds / 1000).toStringAsFixed(1)} seconds');
// Step 10: Recommendations
print('\nš” Recommendations:');
for (var weather in validResults) {
if (weather.temperature > 35) {
print('⢠Stay hydrated in ${weather.city}! It\'s very hot.');
} else if (weather.temperature < 10) {
print('⢠Bring a warm jacket to ${weather.city}.');
}
if (weather.humidity > 70) {
print('⢠High humidity in ${weather.city} (${weather.humidity}%).');
}
}
// Step 11: Temperature range
double tempRange = hottest.temperature - coldest.temperature;
print('\nš”ļø Temperature Range: ${tempRange.toStringAsFixed(0)}°C');
if (tempRange > 20) {
print(' The world has diverse climates today!');
}
}