Jetpack Compose Basics for Beginners | Build Your First Android UI Step by Step

In this blog I'll walk you through creating a fully functional weather app for Android devices. Whether you're a beginner or an experienced developer, this tutorial will help you master the art of building a sleek, user-friendly app to display real-time weather information.

What You'll Learn in This Tutorial:

  • Setting up Android Studio and creating a new project
  • Designing a Professional user-friendly interface with XML layouts
  • Fetching real-time weather data using APIs like OpenWeatherMap
  • Parsing JSON data for meaningful weather insights



First create a nice looking UI for showing weather info. The code snippet for android_main.xml is as follows: 


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="@drawable/background"
    >

    <TextView
        android:id="@+id/cityNameText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:fontFamily="@font/urbanist"
        android:text="City"
        android:textSize="36sp"
        android:textColor="@color/white"
        />

    <TextView
        android:id="@+id/temperatureText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:fontFamily="@font/urbanist"
        android:text="25°"
        android:textColor="#FFBF00"
        android:textSize="60sp"
        android:textStyle="bold"
        android:layout_below="@id/cityNameText"/>

    
    </LinearLayout>

    <ImageView
        android:id="@+id/weatherIcon"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_below="@id/detailsLayout"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="20dp"
        android:elevation="12dp"
        android:src="@drawable/ic_01d"
        android:contentDescription="Weather Icon"
        />

    <TextView
        android:id="@+id/descriptionText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/weatherIcon"
        android:textColor="@color/white"
        android:layout_centerHorizontal="true"
        android:fontFamily="@font/urbanist"
        android:text="Sunny"
        android:textSize="28sp"
        />

   <EditText
        android:id="@+id/cityNameInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/descriptionText"
        android:textColor="#EFEFEF"
        android:padding="12dp"
        android:textColorHint="#BFBFBF"
        android:gravity="center"
        android:fontFamily="@font/urbanist"
        android:textSize="24sp"
        android:layout_marginTop="20dp"
        android:hint="Enter City Name"
        />

    <Button
        android:id="@+id/fetchWeatherButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/cityNameInput"
        android:backgroundTint="#2B3A67"
        android:fontFamily="@font/urbanist"
        android:text="Change City"
        android:textColor="#FFF"
        android:textSize="20sp"
        />
</RelativeLayout>
The code snippet for MainActivity.java is as follows:

package com.codingtutorials.weatherapp;

import androidx.appcompat.app.AppCompatActivity;

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 org.json.JSONException;
import org.json.JSONObject;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainActivity extends AppCompatActivity {
    private TextView cityNameText, temperatureText, humidityText, descriptionText, windText;
    private ImageView weatherIcon;
    private Button refreshButton;
    private EditText cityNameInput;
    private static final String API_KEY = "******************************"; // your own API Key

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        cityNameText = findViewById(R.id.cityNameText);
        temperatureText = findViewById(R.id.temperatureText);
        humidityText = findViewById(R.id.humidityText);
        windText= findViewById(R.id.windText);
        descriptionText = findViewById(R.id.descriptionText);
        weatherIcon = findViewById(R.id.weatherIcon);
        refreshButton  = findViewById(R.id.fetchWeatherButton);
        cityNameInput = findViewById(R.id.cityNameInput);

        refreshButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String cityName = cityNameInput.getText().toString();
                if(!cityName.isEmpty())
                {
                    FetchWeatherData(cityName);
                }
                else
                {
                    cityNameInput.setError("Please enter a city name");
                }
            }
        });



        FetchWeatherData("Mumbai");
    }

    private void FetchWeatherData(String cityName) {

        String url = "https:api.openweathermap.org/data/2.5/weather?q="+cityName + "&appid="+ API_KEY + "&units=metric";
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(() ->
                {
                    OkHttpClient client = new OkHttpClient();
                    Request request = new Request.Builder().url(url).build();
                    try {
                        Response response = client.newCall(request).execute();
                        String result = response.body().string();
                        runOnUiThread(() -> updateUI(result));
                    } catch (IOException e)
                    {
                        e.printStackTrace();;
                    }
                }
           );
    }

    private void updateUI(String result)
    {
        if(result != null)
        {
            try {
                JSONObject jsonObject = new JSONObject(result);
                JSONObject main =  jsonObject.getJSONObject("main");
                double temperature = main.getDouble("temp");
                double humidity = main.getDouble("humidity");
                double windSpeed = jsonObject.getJSONObject("wind").getDouble("speed");

                String description = jsonObject.getJSONArray("weather").getJSONObject(0).getString("description");
                String iconCode = jsonObject.getJSONArray("weather").getJSONObject(0).getString("icon");
                String resourceName = "ic_" + iconCode;
                int resId = getResources().getIdentifier(resourceName, "drawable", getPackageName());
                weatherIcon.setImageResource(resId);

                cityNameText.setText(jsonObject.getString("name"));
                temperatureText.setText(String.format("%.0f°", temperature));
                humidityText.setText(String.format("%.0f%%", humidity));
                windText.setText(String.format("%.0f km/h", windSpeed));
                descriptionText.setText(description);
            } catch (JSONException e)
            {
                e.printStackTrace();
            }
        }
    }
}
Following dependencies needed to be updated in graddle (app level) for accessible web data 
implementation("com.squareup.okhttp3:okhttp:4.9.3")

dependencies { 
implementation("androidx.appcompat:appcompat:1.7.0") implementation("com.google.android.material:material:1.12.0") implementation("androidx.constraintlayout:constraintlayout:2.2.0") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.2.1") androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") implementation("com.squareup.okhttp3:okhttp:4.9.3") }


The code snippet for Android_Manifest.xml is as follows:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.INTERNET">
    <application android:allowbackup="true" android:dataextractionrules="@xml/data_extraction_rules" android:fullbackupcontent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundicon="@mipmap/ic_launcher_round" android:supportsrtl="true" android:theme="@style/Theme.WeatherApp" tools:targetapi="31">
    <activity android:exported="true" android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN">
                <category android:name="android.intent.category.LAUNCHER">
                </category></action>
            </intent-filter>
        </activity>
       <meta-data android:name="preloaded_fonts" android:resource="@array/preloaded_fonts"/>        
    </application>
</manifest>


 

Comments