¿Cómo llamar a una función después de un retraso en Kotlin?

154

Como título, ¿hay alguna forma de llamar a una función después del retraso (1 segundo, por ejemplo) Kotlin?

Nguyen Minh Binh
fuente

Respuestas:

134

Puedes usar Schedule

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

ejemplo (gracias @Nguyen Minh Binh - lo encontré aquí: 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
fuente
16
¡Gracias! Muy facil. Encontré un ejemplo aquí jamie.mccrindle.org/2013/02/… Timer("SettingUp", false).schedule(500) { doSomething() }
Nguyen Minh Binh
9
Se compila si agrega estas dos importaciones: import java.util.Timer e import kotlin.concurrent.schedule
Personalizador
3
@Matias Elorriaga, para mí, poner esto en un nuevo archivo de marca no se compila, incluso agregando las importaciones, dijo el Personalizador
Sulfkain
3
no necesita ponerlo en un archivo, ese método es parte de stdlib, siga el enlace en la primera línea de la respuesta,
Matias Elorriaga
3
Originalmente pensé que esto no se compilaría incluso después de la importación kotlin.concurrent.schedule, porque Kotlin simplemente se quejó de una falta de coincidencia de firma, pero luego me di cuenta de que estaba tratando de pasar un Int en lugar de un Long. Se compiló después de corregir eso.
Joe Lapp
178

También hay una opción para usar Handler -> postDelayed

 Handler().postDelayed({
                    //doSomethingHere()
                }, 1000)
Bogdan Ustyak
fuente
18
Agregue que solo está disponible en Android, ya que la pregunta solicita un método general de kotlin (aunque tiene la etiqueta de Android)
Yoav Sternberg
55
No es constructivo de tu lado. Como resultado, cuando los usuarios busquen en la etiqueta de Android, podría pensar que esta es una respuesta incorrecta.
Bogdan Ustyak
9
Para Android, es mejor usar Handler que Timer: stackoverflow.com/questions/20330355/timertask-or-handler
woprandi
Creo que debería agregar un código para eliminar los controladores después de que finalice la actividad / fragmento.
CoolMind
Esto no se ejecutará en el hilo de la interfaz de usuario si pretendía hacerlo.
AndroidDev
93

Muchas maneras

1. Usando la Handlerclase

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

2. Usando la Timerclase

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

Corta

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

Mas corto

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

3. Usando la Executorsclase

Executors.newSingleThreadScheduledExecutor().schedule({
    TODO("Do something")
}, 2, TimeUnit.SECONDS)
Khemraj
fuente
1
¿Cuál crees que es la mejor solución aquí?
Tamim Attafi
1
Probablemente el primero que usa un controlador. Ver stackoverflow.com/a/40339630/1159930
Markymark
36

Debe importar las siguientes dos bibliotecas:

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

y después de eso úsalo de esta manera:

Timer().schedule(10000){
    //do something
}
jonguer
fuente
27

Podrías launchuna corutina, delayy luego llamar a la función:

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

Si está fuera de una clase o un objeto, GlobalScopehaga que la corutina se ejecute allí; de lo contrario, se recomienda implementarla CoroutineScopeen la clase circundante, lo que permite cancelar todas las corutinas asociadas a ese alcance si es necesario.

Jonas Wilms
fuente
¡Gracias! Extraño, esas corutinas se mencionaron solo en 2018.
CoolMind
@coolMind son estables desde hace unos meses, por lo que son bastante nuevos ...
Jonas Wilms
Sí, de octubre a noviembre, pero existía antes.
CoolMind
23
val timer = Timer()
timer.schedule(timerTask { nextScreen() }, 3000)
varghesekutty
fuente
1
¿Puede explicarme por qué necesito escribir "timerTask" en lugar de solo llaves?
Hugo Passos
2
Creo que lo haces. Timer.schedule()espera un TimerTaskcomo su primer argumento. kotlin.concurrent.timerTask()envuelve el lambda dado en una TimerTaskinstancia. Ver aquí: kotlinlang.org/api/latest/jvm/stdlib/kotlin.concurrent/…
Blieque
También, el ejemplo dado se puede condensar a una línea si el Timerobjeto no se va a utilizar más de una vez, por ejemplo, Timer().schedule(timerTask { ... }, 3000). También está disponible una opción más amigable para Kotlin; ver la respuesta de jonguer.
Blieque
10

Un ejemplo simple para mostrar un brindis después de 3 segundos :

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

fun showToast(){
    Toast.makeText(context, "Its toast!", Toast.LENGTH_SHORT).show()
}
Zeero0
fuente
1
¿Puedo cancelar la llamada?
Eduardo Oliveros
6

Si está buscando un uso genérico, aquí está mi sugerencia:

Crea una clase llamada como Run:

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

Y use así:

Run.after(1000, {
    // print something useful etc.
})
Ogulcan Orhan
fuente
Puede simplificar esto como función de extensión
Vlad
@Ogulcan, más kotlinic lamda Run.after(1000) { toRun() }. ¿Estoy en lo cierto?
binrebin
0

Le recomendé usar SingleThread porque no tiene que matarlo después de usarlo. Además, el método " stop ()" está en desuso en el lenguaje Kotlin.

private fun mDoThisJob(){

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

    }, 1, 1, TimeUnit.SECONDS)
}

Además, puede usarlo para trabajos periódicos. Es muy útil. Si desea hacer un trabajo por cada segundo, puede configurarlo porque los parámetros de la misma:

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

Los valores de TimeUnit son: NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS.

@canerkaseler

Canerkaseler
fuente