Nguyen  Minh Binh
Nguyen Minh Binh

Reputation: 24423

How to call a function after delay in Kotlin?

As the title, is there any way to call a function after delay (1 second for example) in Kotlin?

Upvotes: 286

Views: 353341

Answers (15)

Bogdan Ustyak
Bogdan Ustyak

Reputation: 5839

There is also an option to use Handler -> postDelayed

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

Upvotes: 268

Infomaster
Infomaster

Reputation: 873

if you are call function in UI.

Timer().schedule(1000) {
  activity?.runOnUiThread {
    doSomething()
  }
}

Upvotes: 0

MDT
MDT

Reputation: 1695

Another way to create a redundant job other than this; that does not require the function to be suspend.

   val repeatableJob = CoroutineScope(Dispatchers.IO).launch {
        while (true) {
            delay(1000)
        }
    }

Cancel when you are done - repeatableJob.cancel()

Upvotes: 1

broc.seib
broc.seib

Reputation: 22731

I use the following function(s):

fun <T> delayedAsyncTask(delayMs: Long = 0, task: () -> T): ScheduledFuture<T> {
    return Executors
        .newSingleThreadScheduledExecutor()
        .schedule(Callable<T> { task() }, delayMs, TimeUnit.MILLISECONDS)
}

fun <T> asyncTask(task: () -> T) = delayedAsyncTask(0, task)

Here's a unit test for the delayed function. Use of the returned future is optional of course.

    @Test
    fun `delayed task work correctly`() {
        val future = delayedAsyncTask(1000) {
            "lambda returns hello world"
        }
        assertEquals(false, future.isDone)
        Thread.sleep(1100)
        assertEquals(true, future.isDone)
        assertEquals("lambda returns hello world", future.get())
    }

Upvotes: 1

Khemraj Sharma
Khemraj Sharma

Reputation: 58934

Many Ways

1. Using Handler class

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

2. Using Timer class

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

// Shorter

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


// Shortest

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

3. Using Executors class

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

Upvotes: 243

vignesh
vignesh

Reputation: 490

i suggest to use kotlin coroutine and if you want to cancel it. its simple and light weight.

fun repeatFun(): Job {
    return coroutineScope.launch {  
        while(isActive) {
            //do your work here
            delay(1000)
        }
    }
}

//start the loop
val repeatFun = repeatRequest()

//Cancel the loop
repeatFun.cancel()

Upvotes: 4

canerkaseler
canerkaseler

Reputation: 7468

I recommended using SingleThread because you do not have to kill it after using. Also, "stop()" method is deprecated in Kotlin language.

private fun mDoThisJob(){

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

    }, 1, 1, TimeUnit.SECONDS)
}

Moreover, you can use it for periodical job. It is very useful. If you would like to do job for each second, you can set because parameters of it:

Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);

TimeUnit values are: NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS.

Upvotes: 1

Andy
Andy

Reputation: 810

If you are in a fragment with viewModel scope you can use Kotlin coroutines:

    myViewModel.viewModelScope.launch {
        delay(2000)
        // DoSomething()
    }

Upvotes: 21

dwbrito
dwbrito

Reputation: 5254

If you're using more recent Android APIs the Handler empty constructor has been deprecated and you should include a Looper. You can easily get one through Looper.getMainLooper().

    Handler(Looper.getMainLooper()).postDelayed({
        //Your code
    }, 2000) //millis

Upvotes: 21

Matias Elorriaga
Matias Elorriaga

Reputation: 9150

You can use Schedule

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

example (thanks @Nguyen Minh Binh - found it here: 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()
}

Upvotes: 225

Jonas Wilms
Jonas Wilms

Reputation: 138234

You could launch a coroutine, delay it and then call the function:

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

If you are outside of a class or object prepend GlobalScope to let the coroutine run there, otherwise it is recommended to implement the CoroutineScope in the surrounding class, which allows to cancel all coroutines associated to that scope if necessary.

Upvotes: 65

Ogulcan Orhan
Ogulcan Orhan

Reputation: 5317

If you are looking for generic usage, here is my suggestion:

Create a class named as Run:

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

And use like this:

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

Upvotes: 9

jonguer
jonguer

Reputation: 561

You have to import the following two libraries:

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

and after that use it in this way:

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

Upvotes: 56

Zeero0
Zeero0

Reputation: 2780

A simple example to show a toast after 3 seconds :

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

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

Upvotes: 12

varghesekutty
varghesekutty

Reputation: 1005

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

Upvotes: 32

Related Questions