An Android weather application built with Kotlin that provides real-time weather data and detailed atmospheric metrics based on your current GPS location. No API key required.
| Screen | Description |
|---|---|
| Home | App entry point |
| Weather | Current temperature + 8 key weather stats |
| Details | 12 advanced metrics in scrollable cards |
- Real-time weather fetched from your GPS location
- Two levels of weather data: basic overview and advanced details
- Scrollable card-based UI for detailed metrics
- Bottom navigation between screens
- Portrait-locked orientation for consistent layout
- No API key needed
| Tool | Purpose |
|---|---|
| Kotlin | Primary language |
| XML | UI layouts |
| Gradle | Build system |
| Android Studio | IDE |
| Open-Meteo API | Free weather data, no API key |
| Google Play Services | Fused Location Provider for GPS |
| Material Design 3 | UI components (cards, bottom nav) |
| RecyclerView | Scrollable advanced data cards |
| ConstraintLayout | Responsive screen layouts |
This app uses the free Open-Meteo API β no account or API key required.
Fetches basic current conditions and today's minimum temperature.
Endpoint:
GET https://api.open-meteo.com/v1/forecast
?latitude={lat}
&longitude={lon}
¤t=temperature_2m,relative_humidity_2m,wind_speed_10m,rain,dew_point_2m,sunshine_duration
&daily=temperature_2m_min
Data used:
| Field | Source | Unit | Displayed As |
|---|---|---|---|
temperature_2m |
current | Β°C | Main temperature |
rain |
current | mm | Rain amount |
relative_humidity_2m |
current | % | Humidity |
wind_speed_10m |
current | km/h | Wind speed |
dew_point_2m |
current | Β°C | Dew point |
sunshine_duration |
current | s | Sunshine span |
temperature_2m_min |
daily[0] | Β°C | Min temperature |
Fetches deeper atmospheric data from current, daily, and hourly fields.
Endpoint:
GET https://api.open-meteo.com/v1/forecast
?latitude={lat}
&longitude={lon}
¤t=apparent_temperature,precipitation,showers,snowfall,cloud_cover,direct_radiation,surface_pressure,pressure_msl
&daily=daylight_duration,uv_index_max
&hourly=cape,soil_temperature_0cm
Data used:
| Field | Source | Unit | Displayed As |
|---|---|---|---|
apparent_temperature |
current | Β°C | Apparent Temp |
precipitation |
current | mm | Precipitation |
showers |
current | mm | Showers |
snowfall |
current | cm | Snowfall |
cloud_cover |
current | % | Cloud Cover |
direct_radiation |
current | W/mΒ² | Radiation |
surface_pressure |
current | hPa | Surface Pressure |
pressure_msl |
current | hPa | Sea Level Pressure |
daylight_duration |
daily[0] | s | Daylight Span |
uv_index_max |
daily[0] | - | UV Index Max |
cape |
hourly[0] | J/kg | Storm Energy |
soil_temperature_0cm |
hourly[0] | Β°C | Soil Temp 0cm |
fusedLocationClient.lastLocation
.addOnSuccessListener { location ->
if (location != null) {
fetchData(location.latitude, location.longitude).start()
}
}val url = URL(
"https://api.open-meteo.com/v1/forecast?" +
"latitude=$lat&longitude=$lon&" +
"current=apparent_temperature,precipitation,showers,snowfall," +
"cloud_cover,direct_radiation,surface_pressure,pressure_msl&" +
"daily=daylight_duration,uv_index_max&" +
"hourly=cape,soil_temperature_0cm"
)
val connection = url.openConnection() as HttpsURLConnectionval json = org.json.JSONObject(reader.readText())
val current = json.getJSONObject("current")
val daily = json.getJSONObject("daily")
val hourly = json.getJSONObject("hourly")
val weather = WeatherAdvanced(
apparentTemp = current.optDouble("apparent_temperature", 0.0),
precipitation = current.optDouble("precipitation", 0.0),
cloudCover = current.optDouble("cloud_cover", 0.0),
daylightDuration = daily.getJSONArray("daylight_duration").optDouble(0, 0.0),
uvIndexMax = daily.getJSONArray("uv_index_max").optDouble(0, 0.0),
cape = hourly.getJSONArray("cape").optDouble(0, 0.0),
soilTemp = hourly.getJSONArray("soil_temperature_0cm").optDouble(0, 0.0)
)data class Weather(
val temp: Double,
val rainAmount: Double,
val humidity: Double,
val windSpeed: Double,
val dewPoint: Double,
val sunshineSpan: Double,
val tempMin: Double
)
data class WeatherAdvanced(
val apparentTemp: Double,
val precipitation: Double,
val showers: Double,
val snowfall: Double,
val cloudCover: Double,
val directRadiation: Double,
val daylightDuration: Double,
val surfacePressure: Double,
val pressureMsl: Double,
val uvIndexMax: Double,
val cape: Double,
val soilTemp: Double
)private fun UpdateUI(weather: Weather, lat: Double, lon: Double) {
runOnUiThread {
findViewById<TextView>(R.id.Degree).text = "${weather.temp}Β°C"
findViewById<TextView>(R.id.rain_amount).text = "${weather.rainAmount}mm"
findViewById<TextView>(R.id.humidity_amount).text = "${weather.humidity}%"
findViewById<TextView>(R.id.wind_amount).text = "${weather.windSpeed}km/h"
findViewById<TextView>(R.id.dew_amount).text = "${weather.dewPoint}Β°C"
findViewById<TextView>(R.id.sun_span).text = "${weather.sunshineSpan}s"
findViewById<TextView>(R.id.min_temp).text = "${weather.tempMin}Β°C"
findViewById<TextView>(R.id.latitude).text = "Latitude:%.2f".format(lat)
findViewById<TextView>(R.id.longtitude).text = "Longitude:%.2f".format(lon)
}
}app/
βββ manifests/
β βββ AndroidManifest.xml
βββ kotlin/com/example/weatherapp/
β βββ MainActivity.kt # Home screen
β βββ MainActivity2.kt # Weather overview screen
β βββ MainActivity3.kt # Advanced details screen
β βββ WeatherAdapter.kt # RecyclerView adapter
β βββ Weather.kt # Basic weather data class
β βββ WeatherAdvanced.kt # Advanced weather data class
β βββ WeatherData.kt # RecyclerView item data class
β βββ Navigate.kt # Bottom nav helper
βββ res/
βββ layout/
β βββ activity_main.xml
β βββ activity_main2.xml
β βββ activity_main3.xml
β βββ data_card.xml
βββ menu/
β βββ bottom_nav.xml
βββ color/
βββ nav_item_color.xml
Declared in AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>Location permission is also requested at runtime:
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
1
)- Android Studio (Hedgehog or newer recommended)
- Android SDK 24+
- A physical Android device or an emulator with location mocking enabled
-
Clone the repository
git clone https://github.com/yourusername/weatherapp.git
-
Open in Android Studio
- File β Open β select the project folder
-
Let Gradle sync
- Android Studio will automatically download dependencies
-
Run the app
- Connect a physical device via USB with USB debugging enabled
- Or launch an emulator
- Press Run βΆ or
Shift + F10
-
Grant permissions
- Accept the location permission prompt on first launch
β οΈ A physical device gives the most accurate GPS results. Emulators require manual location mocking via Extended Controls.
In build.gradle (app):
dependencies {
implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}This project is open source and free to use for personal and educational purposes.



