Jak wywołać funkcję po opóźnieniu w Kotlinie?

154

W tytule, czy istnieje sposób wywołania funkcji po opóźnieniu (na przykład 1 sekundę) w Kotlin?

Nguyen Minh Binh
źródło

Odpowiedzi:

134

Możesz użyć harmonogramu

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

przykład (dzięki @Nguyen Minh Binh - znalazłem go tutaj: 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()
}
Matias Elorriaga
źródło
16
Dzięki! Super łatwe. Przykład znalazłem tutaj jamie.mccrindle.org/2013/02/…Timer("SettingUp", false).schedule(500) { doSomething() }
Nguyen Minh Binh
9
Kompiluje się, jeśli dodasz te dwa importy: import java.util.Timer i import kotlin.concurrent.schedule
Customizer
3
@Matias Elorriaga, dla mnie, umieszczanie tego na nowym pliku marki nie kompiluje się, nawet dodając import Customizer powiedział
Sulfkain
3
nie musisz umieszczać go w pliku, ta metoda jest częścią standardowej biblioteki, podążaj za linkiem w pierwszej linii odpowiedzi,
Matias Elorriaga
3
Początkowo myślałem, że to się nie skompiluje nawet po zaimportowaniu kotlin.concurrent.schedule, ponieważ Kotlin tylko narzekał na niezgodność podpisu, ale potem zdałem sobie sprawę, że próbuję przekazać Int zamiast Long. Został skompilowany po poprawieniu tego.
Joe Lapp
178

Istnieje również opcja użycia Handler -> postDelayed

 Handler().postDelayed({
                    //doSomethingHere()
                }, 1000)
Bogdan Ustyak
źródło
18
Dodaj, że jest dostępny tylko na Androida, ponieważ pytanie dotyczy ogólnej metody kotlin (chociaż ma tag Androida)
Yoav Sternberg
5
To nie jest konstruktywne z Twojej strony. W rezultacie, gdy użytkownicy będą przeszukiwać tag Androida, mogą pomyśleć, że to zła odpowiedź.
Bogdan Ustyak
9
W przypadku Androida lepiej jest użyć programu Handler niż Timer: stackoverflow.com/questions/20330355/timertask-or-handler
woprandi
Myślę, że powinieneś dodać kod do usuwania programów obsługi po zakończeniu działania / fragmentu.
CoolMind
Nie będzie to działać w wątku interfejsu użytkownika, jeśli zamierzałeś to zrobić.
AndroidDev
93

Wiele sposobów

1. Korzystanie z Handlerklasy

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

2. Korzystanie z Timerklasy

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

Krótszy

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

Najkrótsza

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

3. Korzystanie z Executorsklasy

Executors.newSingleThreadScheduledExecutor().schedule({
    TODO("Do something")
}, 2, TimeUnit.SECONDS)
Khemraj
źródło
1
i jakie według ciebie jest najlepsze rozwiązanie tutaj?
Tamim Attafi
1
Prawdopodobnie pierwszy korzystający z Handlera. Zobacz stackoverflow.com/a/40339630/1159930
Markymark
36

Musisz zaimportować następujące dwie biblioteki:

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

a potem użyj go w ten sposób:

Timer().schedule(10000){
    //do something
}
jonguer
źródło
27

Mógłbyś launchcoroutine, delaya następnie wywołać funkcję:

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

Jeśli jesteś poza klasą lub obiektem, GlobalScopedołącz poprzednik, aby pozwolić programowi działać w tym miejscu, w przeciwnym razie zaleca się zaimplementowanie CoroutineScopew otaczającej klasie, co pozwala w razie potrzeby anulować wszystkie procedury powiązane z tym zakresem.

Jonas Wilms
źródło
Dzięki! Dziwne, że o korepetycjach wspomniano dopiero w 2018 roku.
CoolMind
@coolMind są stabilne od kilku miesięcy, więc są całkiem nowe ...
Jonas Wilms
Tak, od października do listopada, ale istniało wcześniej.
CoolMind
23
val timer = Timer()
timer.schedule(timerTask { nextScreen() }, 3000)
varghesekutty
źródło
1
Czy możesz mi wyjaśnić, dlaczego muszę napisać „timerTask” zamiast samych nawiasów klamrowych?
Hugo Passos
2
Myśle że robisz. Timer.schedule()oczekuje, że TimerTaskjako pierwszy argument. kotlin.concurrent.timerTask()zawija podaną lambdę w TimerTaskinstancji. Zobacz tutaj: kotlinlang.org/api/latest/jvm/stdlib/kotlin.concurrent/…
Blieque
Również podany przykład można skondensować do jednej linii, jeśli Timerobiekt nie będzie używany więcej niż raz, np Timer().schedule(timerTask { ... }, 3000).. Dostępna jest również opcja bardziej przyjazna Kotlinowi; zobacz odpowiedź Jonguera.
Blieque
10

Prosty przykład pokazujący toast po 3 sekundach :

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

fun showToast(){
    Toast.makeText(context, "Its toast!", Toast.LENGTH_SHORT).show()
}
Zeero0
źródło
1
czy mogę anulować połączenie?
Eduardo Oliveros
6

Jeśli szukasz ogólnego zastosowania, oto moja sugestia:

Utwórz klasę o nazwie Run:

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

I użyj w ten sposób:

Run.after(1000, {
    // print something useful etc.
})
Ogulcan Orhan
źródło
Możesz to uprościć jako funkcję rozszerzenia
Vlad
@Ogulcan, bardziej kotlinic lamda Run.after(1000) { toRun() }. Czy mam rację
binrebin
0

Polecam używanie SingleThread, ponieważ nie musisz go zabijać po użyciu. Ponadto metoda „ stop ()” jest przestarzała w języku Kotlin.

private fun mDoThisJob(){

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

    }, 1, 1, TimeUnit.SECONDS)
}

Ponadto możesz go używać do pracy okresowej. To jest bardzo użyteczne. Jeśli chcesz wykonywać pracę na każdą sekundę, możesz ustawić jej parametry:

Executors.newSingleThreadScheduledExecutor (). ScheduleAtFixedRate (polecenie Runnable, long initialDelay, long period, unit TimeUnit);

Wartości TimeUnit to: NANOSECONDS, MICROSECONDS, MILISECONDS, SECONDS, MINUTES, HOURS, DAYS.

@canerkaseler

canerkaseler
źródło