Як викликати функцію після затримки в Kotlin?


Відповіді:


134

Ви можете використовувати Розклад

inline fun Timer.schedule(
    delay: Long, 
    crossinline action: TimerTask.() -> Unit
): TimerTask (source)

приклад (спасибі @Nguyen Minh Binh - знайшов його тут: http://jamie.mccrindle.org/2013/02/exploring-kotlin-standard-library-part-3.html )

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

Timer("SettingUp", false).schedule(500) { 
   doSomething()
}

16
Дякую! Супер легко. Приклад знайдено тут jamie.mccrindle.org/2013/02/… Timer("SettingUp", false).schedule(500) { doSomething() }
Nguyen Minh Binh

9
Вона компілюється, якщо додати два імпорту: import java.util.Timer та імпорт kotlin.concurrent.schedule
Customizer

3
@Matias Elorriaga, для мене, розміщення цього файлу в новому файлі бренду не компілюється, навіть додаючи імпорт сказав Customizer
Sulfkain

3
вам не потрібно ставити його у файл, цей метод є частиною stdlib, перейдіть за посиланням у першому рядку відповіді,
Matias Elorriaga

3
Спочатку я думав, що це не складеться навіть після імпорту kotlin.concurrent.schedule, тому що Котлін просто скаржився на невідповідність підпису, але потім зрозумів, що намагаюся пройти Int замість Лонга. Він складений після виправлення цього.
Джо Лапп

178

Також є варіант використання Handler -> postDelayed

 Handler().postDelayed({
                    //doSomethingHere()
                }, 1000)

18
Будь ласка, додайте, що він доступний лише на андроїд, оскільки в цьому питанні задається загальний метод котліна (хоча він має тег Android)
Yoav Sternberg

5
Це не конструктивно з вашого боку. У результаті, коли користувачі будуть шукати тег Android, може здатися, що це неправильна відповідь.
Богдан Устяк

9
Для Android, то краще використовувати Handler ніж Таймер: stackoverflow.com/questions/20330355/timertask-or-handler
woprandi

Я думаю, вам слід додати код для видалення обробників після закінчення активності / фрагменту.
CoolMind

Це не працюватиме на потоці інтерфейсу користувача, якщо ви планували це робити.
AndroidDev

93

Багато шляхів

1. Використання Handlerкласу

Handler().postDelayed({
    TODO("Do something")
    }, 2000)

2. Використання Timerкласу

Timer().schedule(object : TimerTask() {
    override fun run() {
        TODO("Do something")
    }
}, 2000)

Коротше

Timer().schedule(timerTask {
    TODO("Do something")
}, 2000)

Найкоротший

Timer().schedule(2000) {
    TODO("Do something")
}

3. Використання Executorsкласу

Executors.newSingleThreadScheduledExecutor().schedule({
    TODO("Do something")
}, 2, TimeUnit.SECONDS)

1
і що, на вашу думку, є найкращим рішенням тут?
Тамім Аттафі

1
Мабуть, перший, хто використовує обробник. Див stackoverflow.com/a/40339630/1159930
Markymark

36

Вам потрібно імпортувати такі дві бібліотеки:

import java.util.*
import kotlin.concurrent.schedule

і після цього використовуйте його таким чином:

Timer().schedule(10000){
    //do something
}

27

Ви можете launchрозробити delayце, а потім викликати функцію:

 /*GlobalScope.*/launch {
   delay(1000)
   yourFn()
 }

Якщо ви перебуваєте за межами класу чи об'єкта, готуйте GlobalScopeдо запуску програми, інакше рекомендується реалізувати CoroutineScopeв оточуючому класі, що дозволяє скасувати всі спроби, пов’язані з цією областю, якщо це необхідно.


Дякую! Дивно, що про корутини згадували лише у 2018 році.
CoolMind

@coolMind вони стабільні з декількох місяців, тому вони зовсім нові ...
Jonas Wilms

Так, з жовтня-листопада, але існували раніше.
CoolMind

23
val timer = Timer()
timer.schedule(timerTask { nextScreen() }, 3000)

1
Чи можете ви поясніть мені, чому мені потрібно писати "timerTask", а не просто дужки?
Уго Пассос

2
Я думаю, що ти. Timer.schedule()очікує TimerTask, що це перший аргумент. kotlin.concurrent.timerTask()загортає дану лямбда в TimerTaskекземпляр. Дивіться тут: kotlinlang.org/api/latest/jvm/stdlib/kotlin.concurrent/…
Blieque

Крім того , цей приклад може бути стиснутий в один рядок , якщо Timerоб'єкт не буде використовуватися більш ніж один раз, наприклад, Timer().schedule(timerTask { ... }, 3000). Також доступний більш зручний для Котліна варіант; див. відповідь jonguer.
Blieque

10

Простий приклад показати тост через 3 секунди :

fun onBtnClick() {
    val handler = Handler()
    handler.postDelayed({ showToast() }, 3000)
}

fun showToast(){
    Toast.makeText(context, "Its toast!", Toast.LENGTH_SHORT).show()
}

1
чи можу я скасувати дзвінок?
Едуардо Оліверос

6

Якщо ви шукаєте загальне використання, ось моя пропозиція:

Створіть клас, названий як Run:

class Run {
    companion object {
        fun after(delay: Long, process: () -> Unit) {
            Handler().postDelayed({
                process()
            }, delay)
        }
    }
}

І використовуйте так:

Run.after(1000, {
    // print something useful etc.
})

Ви можете спростити це як fucntion розширення
Влад

@Ogulcan, більше kotlinic lamda Run.after(1000) { toRun() }. Чи правильно я
бінребін

0

Я рекомендував використовувати SingleThread, оскільки не потрібно вбивати його після використання. Також методом " stop ()" є застарілим мовою Котліна.

private fun mDoThisJob(){

    Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({
        //TODO: You can write your periodical job here..!

    }, 1, 1, TimeUnit.SECONDS)
}

Більше того, ви можете використовувати його для періодичних робіт. Це дуже корисно. Якщо ви хочете виконувати роботу на кожну секунду, ви можете встановити через її параметри:

Execitors.newSingleThreadScheduledExecutor (). ГрафікAtFixedRate (команда Runnable, довгий початковий затримка, тривалий період, одиниця TimeUnit);

Значення TimeUnit: NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS.

@canerkaseler

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.