Question

How to Call a Function After a Delay in Kotlin

kotlinandroid

Question

How can I call a function after a delay in Kotlin, such as waiting 1 second before running it?

For example, I want to delay execution and then invoke a function like this:

fun sayHello() {
    println("Hello")
}

What is the correct way to run that function after a short delay in Kotlin?

Short Answer

By the end of this page, you will understand the main ways to delay code execution in Kotlin, when each approach is appropriate, and why Kotlin coroutines are usually the preferred modern solution. You will also see simple examples, common mistakes, and a small practice project.

Concept

In Kotlin, calling a function after a delay means waiting for some amount of time before running code. There is no single universal delay mechanism that works the same way in every context, because the correct approach depends on where your Kotlin code is running.

The main idea is this:

  • Sometimes you want to block the current thread and wait.
  • Sometimes you want to schedule work without blocking the thread.
  • In modern Kotlin, especially with coroutines, you usually want a non-blocking delay.

Why this matters

Delays are common in real programs:

  • showing a message briefly before moving to the next screen
  • retrying a network request after waiting
  • debouncing user input
  • scheduling background work
  • simulating loading or timeouts in tests

The important distinction: blocking vs non-blocking

A beginner mistake is to think “wait 1 second” is always the same operation. It is not.

Blocking delay

A blocking delay stops the current thread completely.

Example:

Thread.sleep(1000)

While sleeping:

  • that thread cannot do other work
  • a UI thread may freeze
  • it is usually not a good choice for Android UI or coroutine-based code

Non-blocking delay

A non-blocking delay pauses the task without blocking the whole thread.

Example with coroutines:

delay(1000)

While delayed:

  • the thread can be used for other work
  • the program stays more responsive
  • this is the preferred approach in modern Kotlin code

Common approaches in Kotlin

Depending on your environment, you may use:

  • Thread.sleep(...) for simple thread blocking in console code or quick tests
  • Timer / TimerTask for scheduled execution
  • Android Handler().postDelayed(...) in older Android-style code
  • kotlinx.coroutines.delay(...) in modern Kotlin and Android projects

For most modern Kotlin applications, coroutines are the best default choice because they are readable, safe for asynchronous programming, and do not block the thread.

Mental Model

Think of delay like setting a reminder.

  • Thread.sleep is like telling a worker: “Do nothing for 1 second.” The worker is completely unavailable during that time.
  • A scheduled task is like putting a note on a calendar: “Do this 1 second later.” The worker can keep doing other work until then.
  • A coroutine delay is like saying: “Pause my task for 1 second, but let the office keep working.” The task waits, but the whole system does not stop.

This mental model helps you choose the right tool:

  • Need a quick blocking pause? Use thread sleep.
  • Need proper asynchronous waiting? Use coroutines.
  • Need to schedule code in platform-specific code like Android legacy APIs? Use a scheduler like Handler or a timer.
Take Quiz

Syntax and Examples

1. Using Thread.sleep (blocking)

fun sayHello() {
    println("Hello")
}

fun main() {
    Thread.sleep(1000)
    sayHello()
}

This waits 1000 milliseconds, then calls sayHello().

Note: This blocks the current thread. Avoid this on UI threads.

2. Using a Timer

import java.util.Timer
import kotlin.concurrent.schedule

fun sayHello() {
    println("Hello")
}

fun main() {
    Timer().schedule(1000) {
        sayHello()
    }

    Thread.sleep(1500)
}

Here, the function is scheduled to run later.

The extra Thread.sleep(1500) keeps the program alive long enough for the timer task to run in a simple console app.

3. Using Kotlin coroutines (recommended)

import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking

fun sayHello() {
    println("Hello")
}

fun main() = runBlocking {
    delay(1000)
    sayHello()
}

This is the modern Kotlin approach.

  • delay(1000) waits 1 second
  • it does not block the thread like Thread.sleep
  • runBlocking is used here only to make a simple runnable example

4. Android older-style example with Handler

import android.os.Handler
import android.os.Looper

fun sayHello() {
    println("Hello")
}

val handler = Handler(Looper.getMainLooper())
handler.postDelayed({
    sayHello()
}, 1000)

This schedules work on the Android main thread after 1 second.

In modern Android apps, coroutines are often preferred instead.

Step by Step Execution

Consider this coroutine example:

import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking

fun greet() {
    println("Hello after delay")
}

fun main() = runBlocking {
    println("Start")
    delay(1000)
    greet()
    println("End")
}

What happens step by step

  1. main() starts inside runBlocking.
  2. println("Start") runs immediately.
  3. delay(1000) pauses this coroutine for 1000 milliseconds.
  4. During that delay, the thread is not blocked in the same way as Thread.sleep.
  5. After 1 second, execution continues.
  6. greet() is called, so Hello after delay is printed.
  7. println("End") runs last.

Output

Start
Hello after delay
End

Compare with Thread.sleep

fun greet() {
    println("Hello after delay")
}

fun main() {
    println("Start")
    Thread.sleep(1000)
    greet()
    println("End")
}

This produces the same visible output, but the behavior is different internally:

  • Thread.sleep blocks the thread
  • delay pauses the coroutine without blocking the thread in the same way

That difference becomes very important in apps, servers, and concurrent programs.

Real World Use Cases

Common practical uses for delayed execution

UI feedback

Wait briefly before hiding a success message or showing the next screen.

// Conceptually: wait, then continue

Retry logic

If an API request fails, wait before trying again.

// delay(2000) before retrying a request

Debouncing user input

When a user types in a search box, wait a short time before sending a request so you do not search on every keystroke.

Background task scheduling

Run cleanup logic, polling, or status checks after a delay.

Animation and game timing

Wait between events, frames, or actions in simple timing workflows.

Tests and demos

Simulate network latency or asynchronous timing in sample code.

In most production code, developers avoid arbitrary delays unless there is a clear reason. But when timing is part of the feature, choosing the right delay mechanism matters.

Take Quiz

Real Codebase Usage

In real Kotlin projects, delayed execution is usually part of a larger pattern rather than a standalone line of code.

1. Guard clauses before delaying

Developers often check whether work should still happen.

import kotlinx.coroutines.delay

suspend fun sendReminder(isEnabled: Boolean) {
    if (!isEnabled) return

    delay(1000)
    println("Reminder sent")
}

This avoids waiting when the work is unnecessary.

2. Retry with delay

import kotlinx.coroutines.delay

suspend fun fetchWithRetry(fetch: suspend () -> String): String {
    repeat(3) { attempt ->
        try {
            return fetch()
        } catch (e: Exception) {
            if (attempt == 2) throw e
            delay(1000)
        }
    }
    error("Unreachable")
}

This pattern is common in networking code.

3. Delayed UI actions

In Android or desktop UI code, developers may delay navigation, notifications, or state changes.

4. Coroutine-based structured concurrency

In modern codebases, developers usually keep delayed work inside a coroutine scope so it can be cancelled cleanly.

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

fun scheduleMessage(scope: CoroutineScope) {
    scope.launch {
        delay(1000)
        println("Scheduled message")
    }
}

This is better than creating unmanaged background tasks.

5. Error handling around delayed work

A delay does not prevent errors after the delay.

import kotlinx.coroutines.delay

suspend fun delayedParse(value: String): Int {
    delay(500)
    return value.toInt()
}

If value is invalid, parsing still fails. Developers still need validation and exception handling.

Common Mistakes

1. Using Thread.sleep on the UI thread

Broken idea:

Thread.sleep(1000)
updateScreen()

Problem:

  • the UI freezes during the sleep

Better:

  • use coroutines or platform scheduling APIs

2. Forgetting that delay only works in coroutines

Broken code:

import kotlinx.coroutines.delay

fun main() {
    delay(1000)
    println("Hi")
}

Problem:

  • delay is a suspend function
  • it must be called from a coroutine or another suspend function

Correct:

import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    delay(1000)
    println("Hi")
}

3. Assuming milliseconds are seconds

Broken expectation:

Thread.sleep(1)

Problem:

  • this sleeps for 1 millisecond, not 1 second

Correct:

Thread.sleep(1000)

4. Scheduling a timer and letting the program exit too early

import java.util.Timer
import kotlin.concurrent.schedule

fun main() {
    Timer().schedule(1000) {
        println("Hello")
    }
}

Problem:

  • in a simple console program, the process may finish before the scheduled task visibly runs

You need to keep the program alive or use a coroutine-based structure.

5. Starting delayed work without cancellation support

If a screen closes or a request becomes irrelevant, old delayed work may still run.

In real apps, use coroutine scopes tied to lifecycle or request scope when possible.

6. Overusing arbitrary delays

Beginners sometimes add delays to “fix” timing problems.

Example bad habit:

Thread.sleep(500)
loadData()

A delay does not reliably solve synchronization issues. Prefer proper event handling, callbacks, or coroutine coordination.

Comparisons

ApproachBlocks thread?Best forNotes
Thread.sleep(1000)YesSimple console demos or testsEasy, but dangerous on UI threads
Timer().schedule(1000)No, not in the same wayBasic scheduled tasksOlder style; less common in modern Kotlin
Handler.postDelayed(...)NoOlder Android codeAndroid-specific
delay(1000)NoModern Kotlin and Android with coroutinesUsually the preferred choice

Thread.sleep vs delay

FeatureThread.sleepdelay
Blocks the threadYesNo
Works in normal functionsYesNo, needs coroutine/suspend context
Good for UI codeNoYes, usually
Good for modern async KotlinNoYes

When to choose which

  • Choose Thread.sleep for very small console examples or blocking tests.
  • Choose delay for modern Kotlin async code.
  • Choose Handler.postDelayed only when working in Android codebases that still use that style.
  • Choose Timer for simple scheduling when coroutines are not being used.
Take Quiz

Cheat Sheet

Quick reference

Block current thread for 1 second

Thread.sleep(1000)

Delay inside a coroutine for 1 second

delay(1000)

Simple coroutine example

import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    delay(1000)
    println("Done")
}

Schedule with a timer

import java.util.Timer
import kotlin.concurrent.schedule

Timer().schedule(1000) {
    println("Done")
}

Android older-style delayed execution

Handler(Looper.getMainLooper()).postDelayed({
    println("Done")
}, 1000)

Rules to remember

  • Time values here are usually in milliseconds.
  • 1000 milliseconds = 1 second.
  • delay() is a suspend function.
  • Thread.sleep() blocks the thread.
  • Avoid Thread.sleep() on UI threads.
  • Coroutines are the preferred modern Kotlin solution.

Edge cases

  • A scheduled task may never visibly run if the program exits too early.
  • Delayed work may need cancellation if the app state changes.
  • Delays are not a substitute for proper synchronization or event-driven design.

FAQ

How do I delay a function by 1 second in Kotlin?

In modern Kotlin, use a coroutine and call delay(1000). In simple blocking code, you can use Thread.sleep(1000).

Is Thread.sleep() bad in Kotlin?

Not always, but it blocks the current thread. It is usually a poor choice for UI code and modern asynchronous programs.

Why does delay() give an error in a normal function?

Because delay() is a suspend function. It must be called inside a coroutine or another suspend function.

What is the best way to delay code in Android Kotlin?

Usually coroutines are the best option. Older Android code may use Handler.postDelayed().

Are delay values in Kotlin measured in seconds or milliseconds?

Most common APIs shown here use milliseconds. 1000 means 1 second.

Can I call a function later without blocking the app?

Yes. Use coroutines with delay() or another scheduling API such as a timer or Android handler.

Should I use a delay to fix race conditions?

No. Delays are unreliable for synchronization problems. Use proper concurrency tools, lifecycle-aware scopes, or event-based logic instead.

Take Quiz

Mini Project

Description

Build a small Kotlin program that prints a welcome message after a short delay. This helps you practice the difference between immediate execution and delayed execution using coroutines, which is the most common modern Kotlin approach.

Goal

Create a program that waits 1 second, prints a delayed message, then waits another second and prints a second message.

Requirements

  • Use Kotlin coroutines.
  • Wait 1 second before printing the first delayed message.
  • Wait another 1 second before printing the second message.
  • Print a message immediately at the start so the execution order is clear.
Take Quiz

Keep learning

Related questions

View more