How to Create a Weather App with Kotlin and Android

In this tutorial, we will learn how to create a weather app using Kotlin and the Android platform. The app will fetch weather data from an API and display it in a user-friendly format.

Prerequisites

Before getting started, make sure you have the following:

  1. Android Studio installed on your machine.
  2. Basic knowledge of Kotlin programming language.
  3. An API key (we will be using the OpenWeatherMap API in this tutorial).

Setting up the Project

  1. Open Android Studio and click on “Start a new Android Studio project”.
  2. Select “Empty Activity” and click “Next”.
  3. Enter a name for your project and select a package name. Also, make sure the language is set to Kotlin. Click “Finish” to create the project.

Adding necessary dependencies

Open the build.gradle file of your app module and add the following dependencies:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
implementation 'com.google.code.gson:gson:2.8.8'
implementation 'com.github.bumptech.glide:glide:4.12.0'

Once the dependencies are added, sync your project.

Creating the Weather Service

Next, we will create a weather service that fetches weather data from the OpenWeatherMap API. Create a new Kotlin class called WeatherService and add the following code:

import okhttp3.OkHttpClient
import okhttp3.Request
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import com.google.gson.Gson

class WeatherService(private val apiKey: String) {

    private val client = OkHttpClient()

    suspend fun getWeather(city: String): WeatherData {
        val url = "https://api.openweathermap.org/data/2.5/weather?q=$city&appid=$apiKey"
        val request = Request.Builder().url(url).build()

        return withContext(Dispatchers.IO) {
            val response = client.newCall(request).execute()
            val body = response.body()?.string()
            Gson().fromJson(body, WeatherData::class.java)
        }
    }
}

In the getWeather function, we use the OkHttpClient to make a network request to the OpenWeatherMap API. The response is then converted into a WeatherData object using Gson.

Creating the WeatherData model

Next, we will create a Kotlin data class called WeatherData that represents the weather data returned by the API. Add the following code to the WeatherData.kt file:

data class WeatherData(
    val name: String,
    val main: MainData,
    val weather: List<Weather>
)

data class MainData(
    val temp: Double,
    val humidity: Int
)

data class Weather(
    val main: String,
    val description: String,
    val icon: String
)

The WeatherData class contains properties like the city name, temperature, humidity, and a list of weather conditions. The MainData class represents the main weather data, and the Weather class represents a single weather condition.

Creating the MainActivity layout

Open the activity_main.xml layout file and replace the default code with the following:

<RelativeLayout xmlns_android="http://schemas.android.com/apk/res/android"
    xmlns_tools="http://schemas.android.com/tools"
    android_id="@+id/container"
    android_layout_width="match_parent"
    android_layout_height="match_parent"
    android_paddingBottom="@dimen/activity_vertical_margin"
    android_paddingLeft="@dimen/activity_horizontal_margin"
    android_paddingRight="@dimen/activity_horizontal_margin"
    android_paddingTop="@dimen/activity_vertical_margin"
    tools_context=".MainActivity">

    <EditText
        android_id="@+id/cityEditText"
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_hint="Enter city name"
        android_imeOptions="actionSearch"
        android_singleLine="true" />

    <Button
        android_id="@+id/fetchButton"
        android_layout_width="wrap_content"
        android_layout_height="wrap_content"
        android_layout_below="@id/cityEditText"
        android_layout_centerHorizontal="true"
        android_text="Fetch Weather" />

    <TextView
        android_id="@+id/weatherTextView"
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_layout_below="@id/fetchButton"
        android_gravity="center"
        android_textSize="24sp" />

    <ImageView
        android_id="@+id/weatherIconImageView"
        android_layout_width="wrap_content"
        android_layout_height="wrap_content"
        android_layout_below="@id/weatherTextView"
        android_layout_centerHorizontal="true"
        android_layout_marginTop="16dp"
        android_contentDescription="Weather icon" />

</RelativeLayout>

We have added an EditText to enter the city name, a Button to fetch the weather, a TextView to display the weather information, and an ImageView to display the weather icon.

Implementing the MainActivity logic

Open the MainActivity.kt file and replace the default code with the following:

import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {

    private lateinit var weatherService: WeatherService
    private lateinit var cityEditText: EditText
    private lateinit var fetchButton: Button
    private lateinit var weatherTextView: TextView
    private lateinit var weatherIconImageView: ImageView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        weatherService = WeatherService("YOUR_API_KEY")
        cityEditText = findViewById(R.id.cityEditText)
        fetchButton = findViewById(R.id.fetchButton)
        weatherTextView = findViewById(R.id.weatherTextView)
        weatherIconImageView = findViewById(R.id.weatherIconImageView)

        fetchButton.setOnClickListener {
            val city = cityEditText.text.toString()
            if (city.isNotEmpty()) {
                fetchWeather(city)
            }
        }
    }

    private fun fetchWeather(city: String) {
        launch {
            try {
                val weatherData = weatherService.getWeather(city)
                val temperature = weatherData.main.temp.toString()
                val humidity = weatherData.main.humidity.toString()
                val weatherDescription = weatherData.weather.first().description
                val weatherIconUrl = "https://openweathermap.org/img/w/${weatherData.weather.first().icon}.png"

                weatherTextView.text = "Temperature: $temperature ยฐCnHumidity: $humidity%n$weatherDescription"
                Glide.with(this@MainActivity)
                    .load(weatherIconUrl)
                    .into(weatherIconImageView)
            } catch (e: Exception) {
                weatherTextView.text = "Error fetching weather data"
                weatherIconImageView.setImageDrawable(null)
            }
        }
    }
}

Replace 'YOUR_API_KEY' with your actual OpenWeatherMap API key.

In the fetchWeather function, we make use of the weatherService to fetch weather data for the specified city. We then update the UI with the temperature, humidity, weather description, and weather icon using the Glide library.

Testing the App

Connect your Android device or start an emulator, and click on the “Run” button in Android Studio to install and run the app. Enter a city name in the EditText and click the “Fetch Weather” button to see the weather data for that city.

Conclusion

In this tutorial, we learned how to create a weather app using Kotlin and Android. We made use of the OpenWeatherMap API to fetch weather data and displayed it in a user-friendly format. You can further enhance this app by adding more features like a forecast for multiple days or a search history. Feel free to explore and experiment with different features to make the app more useful and interactive.

Related Post