- Published on
Building a Feature-Rich Weather App with Flutter: A Deep Dive
Building a Feature-Rich Weather App with Flutter: A Deep Dive
Table of Contents
Introduction
In this post, I'll take you through the journey of creating a feature-rich weather application using Flutter. This app not only fetches real-time weather data but also provides a polished, user-friendly interface for displaying it. Let's explore the key features, technical implementation, challenges faced, and lessons learned during this project.
Key Features
- Current Location Weather: The app starts by requesting the user's current location and displaying the local weather.
- City Search: Users can search for weather information in any city worldwide.
- Detailed Weather Information: The app displays temperature, weather description, humidity, and wind speed.
- Autocomplete Search: As users type a city name, the app suggests matching cities.
- External Link: Each weather result includes a link to more detailed information on OpenWeatherMap.
Technical Implementation
API Integration
We used the OpenWeatherMap API to fetch weather data. Here's how we make API calls:
Future<void> getWeather() async {
if (city.isNotEmpty) {
final url = Uri.parse('https://api.openweathermap.org/data/2.5/weather?q=$city&appid=$apiKey&units=metric');
final response = await http.get(url);
if (response.statusCode == 200) {
final json = jsonDecode(response.body);
weather = Weather.fromJson(json);
} else {
throw Exception('Failed to load weather data');
}
}
}
Location Services
To get the user's current location, we used the geolocator
package:
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.low);
await getWeatherByCoordinates(position.latitude, position.longitude);
UI Design
We aimed for a clean, intuitive interface. Here's our main weather display structure:
Widget buildWeather(Weather weather) => Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text(weather.cityName, style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
Text('${weather.temperature.toStringAsFixed(1)} °C', style: TextStyle(fontSize: 40)),
Text(weather.description),
Text('Humidity: ${weather.humidity}%'),
Text('Wind Speed: ${weather.windSpeed} m/s'),
],
),
),
);
Challenges and Solutions
1. Implementing Autocomplete
One of the main challenges was implementing the autocomplete feature for city search. We solved this by using the Autocomplete
widget and creating a separate API call to fetch city suggestions:
Autocomplete<String>(
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return const Iterable<String>.empty();
}
return getSuggestions(textEditingValue.text);
},
onSelected: (String selection) {
setState(() {
city = selection.split(',')[0];
});
getWeather();
},
// ... more configuration ...
)
2. Handling Location Permissions
Another challenge was properly handling location permissions. We implemented a robust permission request system:
Future<bool> _handleLocationPermission() async {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Location services are disabled. Please enable the services')));
return false;
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Location permissions are denied')));
return false;
}
}
if (permission == LocationPermission.deniedForever) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Location permissions are permanently denied, we cannot request permissions.')));
return false;
}
return true;
}
Lessons Learned and Best Practices
Error Handling: Implement comprehensive error handling to provide a smooth user experience, even when things go wrong.
API Key Security: Never hardcode API keys in your app. Use environment variables or secure storage solutions.
State Management: For this app, we used
setState()
for simplicity. For larger apps, consider using more robust state management solutions like Provider or Bloc.Code Organization: Keep your code modular and well-organized. We separated our
Weather
model into a separate file for better maintainability.UI Responsiveness: Always provide visual feedback during loading operations to keep users informed.
Setting Up and Running the Project
To run this project:
- Clone the repository:
git clone https://github.com/ibsanju/flutter_weather_app.git
- Navigate to the project directory:
cd flutter_weather_app
- Install dependencies:
flutter pub get
- Create a file named
api_key.dart
in thelib
folder and add your OpenWeatherMap API key:const String apiKey = 'YOUR_API_KEY_HERE';
- Run the app:
flutter run
Make sure you have Flutter installed and set up on your machine before running these commands.
Performance Optimizations
- Debouncing API Calls: We implemented debouncing for the autocomplete feature to reduce unnecessary API calls:
Timer? _debounce;
void onSearchChanged(String query) {
if (_debounce?.isActive ?? false) _debounce!.cancel();
_debounce = Timer(const Duration(milliseconds: 500), () {
getSuggestions(query);
});
}
- Caching: We implemented a simple caching mechanism to store recent weather data, reducing API calls for frequently searched cities.
Future Improvements
In future iterations, we could add features like:
- Weather forecasts for the next few days
- More detailed weather information (e.g., UV index, air quality)
- Weather alerts for severe conditions
- Ability to save favorite locations
Conclusion
Building this weather app with Flutter was an exciting and educational journey. It showcases how Flutter can be used to create cross-platform apps with rich UIs and complex functionalities. The app demonstrates key mobile development concepts like API integration, location services, and autocomplete search.
The process of building this app has not only improved my Flutter skills but also deepened my understanding of mobile app development best practices. I hope this detailed walkthrough helps you in your Flutter journey!
Happy coding!