Android Weather App with Retrofit
Build an Android weather app in Kotlin with Jetpack Compose. You search for a city and see its current weather (temperature, feels-like, wind, conditions) and a 5-day forecast in a scrollable list of cards. Data comes from Open-Meteo, a free weather API that needs no key, through Retrofit. The app shows clear loading and error states, remembers the last result so it still shows something offline, and follows the recommended Android architecture: a ViewModel exposing state as a StateFlow, and a repository hiding where data comes from. You'll learn Retrofit with coroutines, JSON parsing, Compose UI and state, ViewModels, local caching with DataStore, and testing.
- Estimate
- ~12h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
Jetpack Compose · Retrofit · Coroutines
Project roadmap
- 01
Set up the project and networking
~2hCreate an Android project with Jetpack Compose (Empty Activity template). Add Retrofit with the kotlinx.serialization (or Moshi) converter, and the INTERNET permission. Define two Retrofit interfaces: the Open-Meteo geocoding API (search a city, returns coordinates) and the forecast API (current conditions plus 5 daily min and max temperatures and weather codes). Create @Serializable data classes for the responses. Done when: a quick test call logs the forecast for a city.
- 02
Write the repository
~1.5hCreate a WeatherRepository with a suspend function getWeather(city) that looks up the coordinates, fetches the forecast and maps both into your own domain model (CityWeather with the current conditions and a list of DailyForecast), converting weather codes into a description and an icon. Return a Result: CityNotFound, a network error, or success. Done when: the repository returns a CityWeather for a real city and CityNotFound for a made-up one.
- 03
Manage state in a ViewModel
~2hCreate a WeatherViewModel exposing a StateFlow<WeatherUiState> with the states Idle, Loading, Success(data) and Error(message). The search(city) function trims the input, ignores empty searches, sets Loading, and calls the repository in viewModelScope. Cancel a previous search when a new one starts. Done when: calling search moves the state through Loading to Success or Error.
- 04
Build the search and results screens
~2.5hBuild the Compose UI: a search field with a search button (and search from the keyboard's action), a spinner for Loading, a card with the current conditions for Success, and a LazyColumn (or LazyRow) of 5 daily forecast cards with the day name, icon, min and max. Collect the state with collectAsStateWithLifecycle. Done when: searching a city shows its current weather and 5-day forecast.
- 05
Handle errors and cache the last result
~2hShow clear messages for city not found, no internet and server errors, with a Retry button. Save the last successful result as JSON in DataStore and show it on startup, labeled with the time it was fetched, so the app is useful offline. Done when: turning on airplane mode after a search shows the cached weather with its time and a no-connection message.
- 06
Write tests
~2hWrite unit tests for the ViewModel with a fake repository and kotlinx-coroutines-test: a successful search, city not found, a network error and ignoring empty input. Test the repository's mapping with a JSON response saved as a test resource and MockWebServer. Done when: ./gradlew test passes.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack