Wie rufe ich eine Funktion nach einer Verzögerung in Kotlin auf?

153

Gibt es als Titel eine Möglichkeit, eine Funktion nach einer Verzögerung (z. B. 1 Sekunde) in aufzurufen Kotlin ?

Nguyen Minh Binh
quelle

Antworten:

134

Sie können Schedule verwenden

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

Beispiel (danke @Nguyen Minh Binh - fand es hier: 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
quelle
16
Vielen Dank! Super einfach. Hier ein Beispiel gefunden jamie.mccrindle.org/2013/02/… Timer("SettingUp", false).schedule(500) { doSomething() }
Nguyen Minh Binh
9
Es wird kompiliert, wenn Sie diese beiden Importe hinzufügen: import java.util.Timer und import kotlin.concurrent.schedule
Customizer
3
@Matias Elorriaga, für mich, dies in eine neue Markendatei zu setzen, wird nicht kompiliert, sogar die Importe hinzufügen Customizer sagte
Sulfkain
3
Sie müssen es nicht in eine Datei einfügen, diese Methode ist Teil von stdlib, folgen Sie dem Link in der ersten Zeile der Antwort,
Matias Elorriaga
3
Ich dachte ursprünglich, dass dies auch nach dem Import nicht kompiliert werden würde kotlin.concurrent.schedule, da Kotlin sich lediglich über eine Signaturfehlanpassung beschwerte, aber dann wurde mir klar, dass ich versuchte, ein Int anstelle eines Long zu übergeben. Es wurde kompiliert, nachdem das korrigiert wurde.
Joe Lapp
178

Es gibt auch eine Option zu verwenden Handler -> postDelayed

 Handler().postDelayed({
                    //doSomethingHere()
                }, 1000)
Bogdan Ustyak
quelle
18
Bitte fügen Sie hinzu, dass es nur auf Android verfügbar ist, da die Frage nach einer allgemeinen Kotlin-Methode fragt (obwohl es das Android-Tag hat)
Yoav Sternberg
5
Es ist nicht konstruktiv von Ihrer Seite. Infolgedessen, wenn Benutzer Android-Tag suchen, könnte denken, dass dies eine falsche Antwort ist.
Bogdan Ustyak
9
Für Android ist es besser, Handler als Timer zu verwenden: stackoverflow.com/questions/20330355/timertask-or-handler
woprandi
Ich denke, Sie sollten einen Code zum Entfernen von Handlern nach Beendigung der Aktivität / des Fragments hinzufügen.
CoolMind
Dies wird nicht auf dem UI-Thread ausgeführt, wenn Sie dies beabsichtigt haben.
AndroidDev
93

Viele Möglichkeiten

1. HandlerKlasse verwenden

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

2. TimerKlasse verwenden

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

Kürzer

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

Kürzeste

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

3. ExecutorsKlasse verwenden

Executors.newSingleThreadScheduledExecutor().schedule({
    TODO("Do something")
}, 2, TimeUnit.SECONDS)
Khemraj
quelle
1
und was ist Ihrer Meinung nach die beste Lösung hier?
Tamim Attafi
1
Wahrscheinlich der erste, der einen Handler verwendet. Siehe stackoverflow.com/a/40339630/1159930
Markymark
36

Sie müssen die folgenden zwei Bibliotheken importieren:

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

und danach verwenden Sie es auf diese Weise:

Timer().schedule(10000){
    //do something
}
Jonguer
quelle
27

Sie könnten launcheine Coroutine, delayes und dann die Funktion aufrufen:

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

Wenn Sie sich außerhalb einer Klasse oder eines Objekts befinden GlobalScope, müssen Sie die Coroutine dort ausführen, andernfalls wird empfohlen, die CoroutineScopein der umgebenden Klasse zu implementieren , um bei Bedarf alle diesem Bereich zugeordneten Coroutinen abzubrechen.

Jonas Wilms
quelle
Vielen Dank! Seltsam, dass Coroutinen erst 2018 erwähnt wurden.
CoolMind
@coolMind sie sind seit ein paar Monaten stabil, also sind sie ziemlich neu ...
Jonas Wilms
Ja, von Oktober bis November, aber existierte vorher.
CoolMind
21
val timer = Timer()
timer.schedule(timerTask { nextScreen() }, 3000)
varghesekutty
quelle
1
Können Sie mir bitte erklären, warum ich "timerTask" anstatt nur Klammern schreiben muss?
Hugo Passos
2
Ich denke du tust es. Timer.schedule()erwartet ein TimerTaskals erstes Argument. kotlin.concurrent.timerTask()Wraps das gegebene Lambda in eine TimerTaskInstanz. Siehe hier: kotlinlang.org/api/latest/jvm/stdlib/kotlin.concurrent/…
Blieque
Das angegebene Beispiel kann auch zu einer Zeile zusammengefasst werden, wenn das TimerObjekt nicht mehr als einmal verwendet wird, z Timer().schedule(timerTask { ... }, 3000). Eine Kotlin-freundlichere Option ist ebenfalls verfügbar. siehe jonguers antwort.
Blieque
10

Ein einfaches Beispiel, um einen Toast nach 3 Sekunden zu zeigen :

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

fun showToast(){
    Toast.makeText(context, "Its toast!", Toast.LENGTH_SHORT).show()
}
Zeero0
quelle
1
Kann ich den Anruf abbrechen?
Eduardo Oliveros
6

Wenn Sie nach einer generischen Verwendung suchen, ist hier mein Vorschlag:

Erstellen Sie eine Klasse mit dem Namen Run:

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

Und verwenden Sie wie folgt:

Run.after(1000, {
    // print something useful etc.
})
Ogulcan Orhan
quelle
Sie können dies als Erweiterungsfunktion vereinfachen
Vlad
@ Ogcan, mehr kotlinische Lamda Run.after(1000) { toRun() }. Bin ich richtig
binrebin
0

Ich habe die Verwendung von SingleThread empfohlen, da Sie es nach der Verwendung nicht beenden müssen. Außerdem ist die Methode " stop ()" in der Kotlin-Sprache veraltet.

private fun mDoThisJob(){

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

    }, 1, 1, TimeUnit.SECONDS)
}

Darüber hinaus können Sie es für regelmäßige Arbeiten verwenden. Es ist sehr nützlich. Wenn Sie für jede Sekunde einen Job ausführen möchten, können Sie folgende Parameter festlegen:

Executors.newSingleThreadScheduledExecutor (). ScheduleAtFixedRate (Ausführbarer Befehl, lange Anfangsverzögerung, langer Zeitraum, TimeUnit-Einheit);

TimeUnit-Werte sind: NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTEN, STUNDEN, TAGE.

@canerkaseler

canerkaseler
quelle