Avatar ·

Как вызвать функцию с задержкой в Kotlin?

Всем привет! Я новичок в Kotlin и Android-разработке. У меня есть простой сценарий: после нажатия кнопки мне нужно подождать 2 секунды, а затем выполнить какое-то действие (например, показать Toast или изменить текст на экране). Я пытался использовать Thread.sleep(), но это зависает весь интерфейс, и приложение перестаёт реагировать на касания. Вот мой код: ```kotlin button.setOnClickListener { Thread.sleep(2000) // Приложение зависает! textView.text = "Прошло 2 секунды" } ``` Я понимаю, что это неправильно, потому что я блокирую главный поток (UI-поток). Но как сделать это правильно в Kotlin? Я слышал про корутины, Handler и таймеры, но не понимаю, какой подход лучше для простой задержки. Мне нужно решение, которое работает на Android и не требует подключения сторонних библиотек (кроме стандартных). Пожалуйста, объясните на примерах, как правильно реализовать вызов функции через заданный промежуток времени, не блокируя интерфейс. Заранее спасибо! <<>>

Использование корутин (рекомендуемый способ для Kotlin, начиная с версии 1.3)

Самый современный и идиоматичный способ — использовать корутины (coroutines). Они позволяют приостановить выполнение, не блокируя поток. Для этого нужно добавить зависимость kotlinx-coroutines-android (если её нет в проекте):

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'

Теперь вы можете написать:

button.setOnClickListener {
    // Запускаем корутину в главном потоке (Main)
    CoroutineScope(Dispatchers.Main).launch {
        delay(2000) // Задержка 2 секунды, не блокирует UI
        textView.text = "Прошло 2 секунды"
    }
}

Объяснение по шагам:

  • CoroutineScope(Dispatchers.Main) — создаём область видимости корутины, привязанную к главному потоку (UI).
  • launch — запускает новую корутину. Она выполняется параллельно с основным кодом.
  • delay(2000) — приостанавливает корутину на 2 секунды. В это время поток может выполнять другие задачи (например, обрабатывать касания).
  • После задержки код продолжается — мы обновляем textView.

Важно: Если вы используете Activity или Fragment, лучше привязать корутину к жизненному циклу, чтобы избежать утечек памяти. Для этого используйте lifecycleScope (в Activity) или viewModelScope (в ViewModel):

// В Activity
button.setOnClickListener {
    lifecycleScope.launch {
        delay(2000)
        textView.text = "Прошло 2 секунды"
    }
}

Для этого нужна зависимость:

implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'

Альтернативный способ: Handler + postDelayed (для старых проектов)

Если вы не хотите использовать корутины (например, проект на Java или очень старая версия Kotlin), подойдёт Handler:

button.setOnClickListener {
    Handler(Looper.getMainLooper()).postDelayed({
        textView.text = "Прошло 2 секунды"
    }, 2000)
}

Этот код отправляет сообщение в очередь главного потока через 2 секунды. Он не блокирует UI, но менее гибок, чем корутины (сложнее отменять, обрабатывать ошибки и т.д.).

Советы для начинающих

  • Не используйте Thread.sleep() в UI-потоке — это гарантированно приведёт к зависанию.
  • Корутины — стандарт де-факто для асинхронных операций в современном Kotlin. Освоить их стоит, даже если сейчас кажется сложно.
  • Для простой задержки delay() — идеальный выбор.

Надеюсь, это помогло! Если остались вопросы — спрашивайте.

<<>>

Использование Timer (ещё один простой вариант)

Можно использовать встроенный класс Timer из стандартной библиотеки Java. Он работает в фоновом потоке, поэтому не блокирует UI. Однако будьте осторожны: после задержки нужно переключиться обратно на главный поток для обновления интерфейса.

button.setOnClickListener {
    Timer().schedule(object : TimerTask() {
        override fun run() {
            // Здесь мы в фоновом потоке, поэтому используем runOnUiThread
            runOnUiThread {
                textView.text = "Прошло 2 секунды"
            }
        }
    }, 2000)
}

Этот метод работает, но имеет недостатки:

  • Нужно явно переключаться на UI-поток через runOnUiThread.
  • Таймер не отменяется автоматически при уничтожении Activity (может вызвать утечку).
  • Код становится более громоздким по сравнению с корутинами.

Когда использовать: Если вы пишете чистую Java-часть проекта или по каким-то причинам не можете добавить корутины. В остальных случаях лучше выбрать первый ответ.