Thuta Learning
ProjectsMobile Developmentintermediate

Project — Weather App (Retrofit + Coroutines)

Relax. We'll talk through this in plain words — no textbook voice.

What you'll walk away with

  • Understand Project — Weather App (Retrofit + Coroutines) without any of the intimidation
  • Be able to run Android Studio/Compose code yourself
  • Apply this concept straight away in a real project

Let's think about it this way for a second

A network-based app needs to handle three states in the UI — loading (fetching data), success (data received), and error (network failed) — the user should always know 'what's going on' (you can't just leave a blank screen). The pattern `sealed class UiState { object Loading; data class Success(val data: WeatherResponse); data class Error(val message: String) }` is commonly used for managing this kind of state.

Let's connect this to a real scenario

Type a city name into the TextField and click Search — the ViewModel sets `uiState = UiState.Loading` and calls `weatherApi.getWeather(city)` inside a coroutine. On success it moves to `UiState.Success(response)`; on failure (network down, city not found) it moves to `UiState.Error("...")`. The UI then renders differently based on state: `when (uiState) { is Loading -> CircularProgressIndicator(); is Success -> WeatherCard(...); is Error -> ErrorMessage(...) }`.

Let's look at it together

kotlin
sealed class WeatherUiState {
    object Loading : WeatherUiState()
    data class Success(val data: WeatherResponse) : WeatherUiState()
    data class Error(val message: String) : WeatherUiState()
}

class WeatherViewModel @Inject constructor(
    private val api: WeatherApi
) : ViewModel() {
    var uiState by mutableStateOf<WeatherUiState>(WeatherUiState.Loading)
        private set

    fun search(city: String) {
        uiState = WeatherUiState.Loading
        viewModelScope.launch {
            uiState = try {
                WeatherUiState.Success(api.getWeather(city))
            } catch (e: Exception) {
                WeatherUiState.Error("Could not load weather for $city")
            }
        }
    }
}
You should see
Type in a city name and search, and you should see a loading spinner followed by the weather data (or an error message) on screen.

Try it in 5 minutes

Build the Weather app yourself (search TextField + Loading/Success/Error UI) — try typing a wrong city name to trigger the error state.

One thing to watch out for

Watch out for API rate limits — free-tier weather APIs usually cap requests per day, and testing repeatedly can burn through that limit fast.

Easy traps

  • Leaving every error as one generic 'Something went wrong' message — users understand a lot more when you distinguish a network error from a city-not-found error
  • Only testing the loading state on the emulator's fast network — you should also test slow/no-network scenarios

Now try it yourself

Build the Weather app yourself (search TextField + Loading/Success/Error UI) — try typing a wrong city name to trigger the error state.

You'll know it worked when: Type in a city name and search, and you should see a loading spinner followed by the weather data (or an error message) on screen.

Project — Weather App (Retrofit + Coroutines) | Thuta Learning