Home  /  Blog  /  Prayer Times Android Kotlin

Build a Prayer Times App for Android with Kotlin

Kotlin10 min readNovember 2026

This post walks you through building a native Android prayer times app in Kotlin. You will get the user's GPS location, fetch prayer times from UmmahAPI, display them with Material Design, and schedule local notifications for each prayer.

Project Setup

Create a new Android project in Android Studio. Choose "Empty Activity", set the language to Kotlin, and set the minimum SDK to API 26 (Android 8.0). That gives you access to modern scheduling APIs without extra workarounds.

Open your build.gradle (Module: app) file and add these dependencies:

// build.gradle (Module: app)
dependencies {
    // Retrofit for HTTP requests
    implementation("com.squareup.retrofit2:retrofit:2.11.0")
    implementation("com.squareup.retrofit2:converter-gson:2.11.0")

    // Kotlin coroutines
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3")

    // Location services
    implementation("com.google.android.gms:play-services-location:21.3.0")

    // Material Design 3
    implementation("com.google.android.material:material:1.12.0")
}

Sync the project after saving. These are all real package names from Maven Central and Google Maven.

Permissions and Manifest

Prayer times depend on location, so you need both location permissions and the exact alarm permission for scheduling. Open AndroidManifest.xml and add:

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<!-- Inside <application> tag -->
<receiver
    android:name=".PrayerAlarmReceiver"
    android:exported="false" />

At runtime, you must request ACCESS_FINE_LOCATION and POST_NOTIFICATIONS from the user. Android 12 and above also require you to check that the app can schedule exact alarms. Do that before setting any alarm.

Get the Device Location

Use FusedLocationProviderClient to get the last known location. This is faster than requesting a fresh GPS fix and works well for prayer times since precision to two decimal places is more than enough.

// LocationHelper.kt
import android.annotation.SuppressLint
import android.content.Context
import com.google.android.gms.location.LocationServices
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

data class LatLng(val lat: Double, val lng: Double)

@SuppressLint("MissingPermission")
suspend fun getLastLocation(context: Context): LatLng? {
    val client = LocationServices.getFusedLocationProviderClient(context)
    return suspendCancellableCoroutine { cont ->
        client.lastLocation.addOnSuccessListener { location ->
            if (location != null) {
                cont.resume(LatLng(location.latitude, location.longitude))
            } else {
                cont.resume(null)
            }
        }.addOnFailureListener {
            cont.resume(null)
        }
    }
}

Call this from a coroutine inside your ViewModel or Activity after the location permission is granted.

Fetch Prayer Times from UmmahAPI

The UmmahAPI prayer times endpoint takes a latitude and longitude and returns today's prayer times. Set up a Retrofit service interface for it.

// PrayerTimesService.kt
import retrofit2.http.GET
import retrofit2.http.Query

data class PrayerTimes(
    val Fajr: String,
    val Sunrise: String,
    val Dhuhr: String,
    val Asr: String,
    val Maghrib: String,
    val Isha: String
)

data class PrayerTimesResponse(val data: PrayerTimes)

interface PrayerTimesService {
    @GET("api/prayer-times")
    suspend fun getTodayTimes(
        @Query("lat") lat: Double,
        @Query("lng") lng: Double
    ): PrayerTimesResponse
}
// RetrofitClient.kt
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitClient {
    private const val BASE_URL = "https://ummahapi.com/"

    val prayerTimesService: PrayerTimesService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(PrayerTimesService::class.java)
    }
}

Now fetch the times from your ViewModel:

// PrayerTimesViewModel.kt
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch

class PrayerTimesViewModel(app: Application) : AndroidViewModel(app) {

    val prayerTimes = MutableLiveData<PrayerTimes?>()
    val error = MutableLiveData<String?>()

    fun loadTimes(lat: Double, lng: Double) {
        viewModelScope.launch {
            try {
                val response = RetrofitClient.prayerTimesService.getTodayTimes(lat, lng)
                prayerTimes.postValue(response.data)
            } catch (e: Exception) {
                error.postValue(e.message)
            }
        }
    }
}

Tip. Register for a free API key and add it as a query parameter ?key=YOUR_KEY to remove the 5,000 request rate limit. Store the key in your local.properties file and read it through BuildConfig, not hardcoded in source.

Display Times with Material Design

Use a RecyclerView with Material Design 3 cards to show each prayer and its time. First define the card layout in res/layout/item_prayer.xml:

<!-- res/layout/item_prayer.xml -->
<com.google.android.material.card.MaterialCardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginHorizontal="16dp"
    android:layout_marginVertical="6dp"
    app:cardCornerRadius="12dp"
    app:cardElevation="2dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="16dp">

        <TextView
            android:id="@+id/prayerName"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textAppearance="@style/TextAppearance.Material3.TitleMedium" />

        <TextView
            android:id="@+id/prayerTime"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="@style/TextAppearance.Material3.BodyLarge" />
    </LinearLayout>

</com.google.android.material.card.MaterialCardView>
// PrayerAdapter.kt
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class PrayerAdapter(private var items: List<Pair<String, String>>) :
    RecyclerView.Adapter<PrayerAdapter.ViewHolder>() {

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val name: TextView = view.findViewById(R.id.prayerName)
        val time: TextView = view.findViewById(R.id.prayerTime)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_prayer, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.name.text = items[position].first
        holder.time.text = items[position].second
    }

    override fun getItemCount() = items.size

    fun update(newItems: List<Pair<String, String>>) {
        items = newItems
        notifyDataSetChanged()
    }
}

In your Activity, observe the ViewModel and pass a list of name/time pairs to the adapter:

// MainActivity.kt (excerpt)
viewModel.prayerTimes.observe(this) { times ->
    if (times != null) {
        val items = listOf(
            Pair("Fajr", times.Fajr),
            Pair("Sunrise", times.Sunrise),
            Pair("Dhuhr", times.Dhuhr),
            Pair("Asr", times.Asr),
            Pair("Maghrib", times.Maghrib),
            Pair("Isha", times.Isha)
        )
        adapter.update(items)
        schedulePrayerAlarms(times)
    }
}

Schedule Prayer Notifications with AlarmManager

Parse each prayer time string into a Calendar object and set an exact alarm. The API returns times in HH:mm format, so splitting on ":" gives you the hour and minute.

// AlarmScheduler.kt
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import java.util.Calendar

fun schedulePrayerAlarms(context: Context, times: PrayerTimes) {
    val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

    val prayers = mapOf(
        "Fajr" to times.Fajr,
        "Dhuhr" to times.Dhuhr,
        "Asr" to times.Asr,
        "Maghrib" to times.Maghrib,
        "Isha" to times.Isha
    )

    prayers.entries.forEachIndexed { index, (name, timeStr) ->
        val parts = timeStr.split(":")
        if (parts.size < 2) return@forEachIndexed

        val hour = parts[0].toIntOrNull() ?: return@forEachIndexed
        val minute = parts[1].toIntOrNull() ?: return@forEachIndexed

        val calendar = Calendar.getInstance().apply {
            set(Calendar.HOUR_OF_DAY, hour)
            set(Calendar.MINUTE, minute)
            set(Calendar.SECOND, 0)
        }

        // Skip if the time has already passed today
        if (calendar.timeInMillis <= System.currentTimeMillis()) return@forEachIndexed

        val intent = Intent(context, PrayerAlarmReceiver::class.java).apply {
            putExtra("prayer_name", name)
        }

        val pendingIntent = PendingIntent.getBroadcast(
            context,
            index,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )

        alarmManager.setExactAndAllowWhileIdle(
            AlarmManager.RTC_WAKEUP,
            calendar.timeInMillis,
            pendingIntent
        )
    }
}

Now create the PrayerAlarmReceiver to show the notification when an alarm fires:

// PrayerAlarmReceiver.kt
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat

class PrayerAlarmReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        val prayerName = intent.getStringExtra("prayer_name") ?: "Prayer"
        val channelId = "prayer_times_channel"

        val manager = context.getSystemService(Context.NOTIFICATION_SERVICE)
            as NotificationManager

        val channel = NotificationChannel(
            channelId,
            "Prayer Times",
            NotificationManager.IMPORTANCE_HIGH
        )
        manager.createNotificationChannel(channel)

        val notification = NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.drawable.ic_prayer)
            .setContentTitle("$prayerName Time")
            .setContentText("It's time for $prayerName.")
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setAutoCancel(true)
            .build()

        manager.notify(prayerName.hashCode(), notification)
    }
}

Tip. On Android 12 and above, call alarmManager.canScheduleExactAlarms() before setting alarms. If it returns false, send the user to Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM so they can grant permission manually.

Fetch a Full Month for Caching

Fetching times every day uses more network calls than needed. UmmahAPI lets you request a full month at once by adding month and year parameters. Store the result in a local database using Room so the app works offline.

// Fetch a full month of prayer times
// GET https://ummahapi.com/api/prayer-times?lat=21.42&lng=39.82&month=11&year=2026

@GET("api/prayer-times")
suspend fun getMonthTimes(
    @Query("lat") lat: Double,
    @Query("lng") lng: Double,
    @Query("month") month: Int,
    @Query("year") year: Int
): MonthlyPrayerTimesResponse

The response contains an array of daily prayer time objects. Store each day as a Room entity keyed by date. On app start, check if today's data is already in the database before making a network call. This also keeps you well under the rate limit. See the full API docs for the response shape.

Show Calculation Methods to the User

Different regions use different prayer time calculation methods. UmmahAPI has 23 of them. You can let the user pick from a settings screen and pass the selected method ID in your requests. Fetch the list once and store it as preferences.

// Fetch available calculation methods
// GET https://ummahapi.com/api/prayer-times/methods

@GET("api/prayer-times/methods")
suspend fun getCalculationMethods(): MethodsResponse

Display the methods in a settings screen using a ListPreference or a simple AlertDialog with a radio list. Save the chosen method ID with SharedPreferences and include it in every prayer times request as a method query parameter.

FAQ

How do I get prayer times by GPS location in Android Kotlin?

Use FusedLocationProviderClient from Google Play Services to read the device's latitude and longitude. Then pass those values to https://ummahapi.com/api/prayer-times?lat=LAT&lng=LNG. The API returns Fajr, Sunrise, Dhuhr, Asr, Maghrib, and Isha times for today.

Which HTTP library should I use for API calls in an Android Kotlin app?

Retrofit 2 with the Gson converter is the most common choice. Add com.squareup.retrofit2:retrofit:2.11.0 and com.squareup.retrofit2:converter-gson:2.11.0 to your Gradle file. It works cleanly with Kotlin suspend functions and coroutines.

How do I schedule prayer time notifications in Android?

Parse each prayer time string into a Calendar object and use AlarmManager.setExactAndAllowWhileIdle to fire a BroadcastReceiver at that exact time. Inside the receiver, build and post a notification using NotificationCompat.Builder. Fetch fresh times from UmmahAPI each day and reschedule the alarms.

Does UmmahAPI support different prayer calculation methods for Android apps?

Yes. Call https://ummahapi.com/api/prayer-times/methods to get the full list of 23 methods. Store the user's preferred method ID in SharedPreferences and append it as a method query parameter in your prayer times requests.

Start building with UmmahAPI

UmmahAPI is free to use and gives you prayer times, Quran data, Qibla direction, and more in a single API.

Read the docs