Як викликати функцію після затримки в 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.