Как вызвать функцию с задержкой в Kotlin: полный гайд с кодом

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему вам это нужно прямо сейчас

Представьте: вы пишете приложение, и вам нужно показать пользователю уведомление через 5 секунд после нажатия кнопки. Или выполнить запрос к серверу только через 2 секунды после того, как пользователь закончил вводить текст. Или просто сделать красивую анимацию с задержкой. Без умения вызывать функцию с задержкой в Kotlin — никуда.

Этот вопрос — один из самых популярных на Stack Overflow (тысячи просмотров!), и не зря. В Kotlin есть целых 4 способа сделать отложенный вызов, и каждый подходит для своей ситуации. В этой статье мы разберём их все: от простого delay() в корутинах до классического Handler для Android. Вы узнаете, какой метод выбрать и почему, а главное — увидите рабочий код, который можно сразу скопировать в свой проект.

Способ 1: Корутины и delay() (современный и предпочтительный)

Это самый элегантный и рекомендуемый способ в современном Kotlin. Корутины — это лёгкие потоки, которые не блокируют основной поток. Метод delay() приостанавливает корутину на указанное время, а затем возобновляет её.

Для работы с корутинами нужно добавить зависимость в build.gradle.kts:

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")

А вот как это выглядит в коде:

import kotlinx.coroutines.*

fun main() = runBlocking {
    println("Старт: ${System.currentTimeMillis()}")

    // Запускаем корутину с задержкой
    launch {
        delay(3000L) // ждём 3 секунды
        println("Прошло 3 секунды: ${System.currentTimeMillis()}")
        myDelayedFunction() // вызываем нужную функцию
    }

    println("Ждём... (это выполнится сразу)")
}

fun myDelayedFunction() {
    println("Функция выполнена!")
}

Важно: delay() — это приостанавливающая функция (suspend function). Её можно вызывать только внутри корутины или другой suspend-функции. Если вы попробуете вызвать delay() вне корутины, компилятор выдаст ошибку.

Как сделать отложенный вызов в Android с корутинами

В Android-разработке корутины — стандарт де-факто. Вот пример для Activity:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.coroutines.*

class MainActivity : AppCompatActivity() {

    private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())

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

        // Через 2 секунды показать тост
        scope.launch {
            delay(2000L)
            showToast("Прошло 2 секунды!")
        }
    }

    private fun showToast(message: String) {
        android.widget.Toast.makeText(this, message, android.widget.Toast.LENGTH_SHORT).show()
    }

    override fun onDestroy() {
        super.onDestroy()
        scope.cancel() // отменяем все задачи при уничтожении Activity
    }
}

Обратите внимание: мы используем Dispatchers.Main, чтобы работать с UI. И обязательно отменяем scope в onDestroy(), чтобы избежать утечек памяти.

Способ 2: Handler и postDelayed() (классика Android)

Если вы пишете под Android и не хотите (или не можете) использовать корутины, старый добрый Handler всё ещё работает. Этот метод был популярен до эры корутин.

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    private val handler = Handler(Looper.getMainLooper())

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

        // Вызов функции через 5 секунд
        handler.postDelayed({
            showToast("Handler сработал через 5 секунд!")
        }, 5000L)
    }

    private fun showToast(message: String) {
        android.widget.Toast.makeText(this, message, android.widget.Toast.LENGTH_SHORT).show()
    }

    override fun onDestroy() {
        super.onDestroy()
        handler.removeCallbacksAndMessages(null) // очищаем все отложенные задачи
    }
}

Плюсы: простота, работает на старых версиях Android.
Минусы: легко забыть отменить задачу и получить утечку памяти. Код становится громоздким при большом количестве задержек.

Способ 3: Timer и TimerTask (для Java-разработчиков)

Этот способ пришёл из Java. Он тоже работает, но считается устаревшим для Android (может вызвать проблемы с жизненным циклом).

import java.util.*

fun main() {
    println("Старт: ${System.currentTimeMillis()}")

    Timer().schedule(object : TimerTask() {
        override fun run() {
            println("Timer сработал через 4 секунды: ${System.currentTimeMillis()}")
            myDelayedFunction()
        }
    }, 4000L)

    println("Программа продолжает работать...")
    Thread.sleep(5000L) // чтобы программа не завершилась сразу
}

fun myDelayedFunction() {
    println("Функция из Timer выполнена!")
}

Внимание: Timer выполняется в фоновом потоке. Если вы работаете с UI в Android, нужно переключиться на главный поток с помощью runOnUiThread.

Способ 4: Thread.sleep() (почти никогда не используйте)

Технически, вы можете просто усыпить поток на нужное время, а потом вызвать функцию. Но это плохая практика, особенно в Android:

fun main() {
    println("Старт")
    Thread.sleep(3000L) // блокирует весь поток на 3 секунды!
    println("Прошло 3 секунды")
    myDelayedFunction()
}

Почему это плохо:
- Блокирует поток. В Android это приведёт к зависанию UI (ANR — Application Not Responding).
- Никакой гибкости: нельзя отменить задачу, нельзя запустить несколько параллельных задержек.
- Используйте sleep() только в учебных примерах или в фоновых потоках, где это абсолютно необходимо.

Сравнение всех способов

Чтобы вам было проще выбрать, вот сводная таблица:

  • Coroutines + delay() — современно, не блокирует поток, легко отменять. Лучший выбор для новых проектов.
  • Handler + postDelayed() — классика Android, подходит для простых задач. Требует ручного управления отменой.
  • Timer + TimerTask — устаревший, не рекомендован для Android. Работает в фоновом потоке.
  • Thread.sleep() — блокирует поток. Избегайте в продакшене.

Как отменить отложенный вызов

Иногда нужно отменить запланированную задачу (например, пользователь ушёл

Блоги

Рекомендаций по книгам